ATLAS Offline Software
Loading...
Searching...
No Matches
python.MetaReader Namespace Reference

Functions

 ignore_missing_dictionary_warnings (func)
 read_metadata (filenames, file_type=None, mode='lite', promote=None, meta_key_filter=None, unique_tag_info_values=True, ignoreNonExistingLocalFiles=False, normalize_type_names=False)
 _check_project ()
 _get_pfn (filename)
 _read_guid (filename)
 _get_entry_value (entry, field_name, type_name)
 _rntuple_type_to_class_name (type_name)
 _branch_name_to_field_name (branch_name)
 _extract_fields (obj)
 _extract_fields_bsmd (value)
 _convert_value (value, aux=None)
 _get_attribute_val (iov_container, attr_name, attr_idx)
 _extract_fields_iov (iov_container, idx_range)
 _extract_iov_for_run (iov_container, run)
 _extract_iov_detailed (iov_container)
 _extract_fields_iovmdc (value)
 _extract_fields_esi (value)
 _extract_fields_ef (value)
 _extract_fields_cbk (interface=None, aux=None)
 _extract_fields_fmd (interface=None, aux=None)
 _extract_fields_tmd (interface=None, aux=None)
 _extract_fields_triggermenu (interface, aux)
 _extract_fields_triggermenujson (interface, aux)
 _convert_event_type_user_type (value)
 _convert_event_type_bitmask (value)
 make_lite (meta_dict)
 make_peeker (meta_dict)
 promote_keys (meta_dict, mode)
 convert_itemList (metadata, layout)
 dataheader_nentries (infile)
dict get_meta_filter (mode="lite", meta_key_filter=None)
 denormalize_metadata_types (metadata_dict)
 should_keep_meta (normalizedName, typeName, meta_filter)

Variables

 msg = logging.getLogger('MetaReader')
 regexEventStreamInfo = re.compile(r'^EventStreamInfo(_p\d+)?$')
 regexIOVMetaDataContainer = re.compile(r'^IOVMetaDataContainer(_p\d+)?$')
 regexByteStreamMetadataContainer = re.compile(r'^ByteStreamMetadataContainer(_p\d+)?$')
 regexXAODCutBookkeeperContainer = re.compile(r'^xAOD::CutBookkeeperContainer(_v\d+)?$')
 regexXAODCutBookkeeperContainerAux = re.compile(r'^xAOD::CutBookkeeperAuxContainer(_v\d+)?$')
 regexXAODEventFormat = re.compile(r'^xAOD::EventFormat(_v\d+)?$')
 regexXAODFileMetaData = re.compile(r'^xAOD::FileMetaData(_v\d+)?$')
 regexXAODFileMetaDataAux = re.compile(r'^xAOD::FileMetaDataAuxInfo(_v\d+)?$')
 regexXAODFileMetaDataAuxDyn = re.compile(r'^(xAOD::)?FileMetaData.*AuxDyn(\.[a-zA-Z0-9]+)?$')
 regexXAODTriggerMenu = re.compile(r'^DataVector<xAOD::TriggerMenu(_v\d+)?>$')
 regexXAODTriggerMenuAux = re.compile(r'^xAOD::TriggerMenuAuxContainer(_v\d+)?$')
 regexXAODTriggerMenuJson = re.compile(r'^DataVector<xAOD::TriggerMenuJson(_v\d+)?>$')
 regexXAODTriggerMenuJsonAux = re.compile(r'^xAOD::TriggerMenuJsonAuxContainer(_v\d+)?$')
 regexXAODTruthMetaData = re.compile(r'^DataVector<xAOD::TruthMetaData(_v\d+)?>$')
 regexXAODTruthMetaDataAux = re.compile(r'^xAOD::TruthMetaDataAuxContainer(_v\d+)?$')
 regex_cppname = re.compile(r'^([\w:]+)(<.*>)?$')
 regex_persistent_class = re.compile(r'^([a-zA-Z]+(_[pv]\d+)?::)*[a-zA-Z]+_[pv]\d+$')
 regex_BS_files = re.compile(r'^(\w+):.*((\.D?RAW\..*)|(\.data$))')
 regex_URI_scheme = re.compile(r'^([A-Za-z0-9\+\.\-]+)\:')
list lite_primary_keys_to_keep
list lite_TagInfo_keys_to_keep
list trigger_keys
dict trigger_menu_json_map
dict _rntuple_integer_types
dict _rntuple_fundamental_types = {'bool', 'char', 'float', 'double', *_rntuple_integer_types}

Function Documentation

◆ _branch_name_to_field_name()

_branch_name_to_field_name ( branch_name)
protected
Convert a TTree branch name to the name of the equivalent RNTuple field.

RNTuple field names have all non-alphanumeric characters replaced by underscores
(e.g. L1DR-EM15TAU12I-J25 becomes L1DR_EM15TAU12I_J25). The "Aux."/"AuxDyn."
separator of the TTree branch names is kept.

Definition at line 1199 of file MetaReader.py.

1199def _branch_name_to_field_name(branch_name):
1200 """Convert a TTree branch name to the name of the equivalent RNTuple field.
1201
1202 RNTuple field names have all non-alphanumeric characters replaced by underscores
1203 (e.g. L1DR-EM15TAU12I-J25 becomes L1DR_EM15TAU12I_J25). The "Aux."/"AuxDyn."
1204 separator of the TTree branch names is kept.
1205 """
1206 parts = re.split(r'(Aux(?:Dyn)?\.)', branch_name, maxsplit=1)
1207 return ''.join(part if i % 2 else re.sub(r'[^A-Za-z0-9]', '_', part)
1208 for i, part in enumerate(parts))
1209
1210

◆ _check_project()

_check_project ( )
protected

Definition at line 1087 of file MetaReader.py.

1087def _check_project():
1088 import os
1089 if 'AthSimulation_DIR' in os.environ:
1090 return 'AthSimulation'
1091 if 'AthGeneration_DIR' in os.environ:
1092 return 'AthGeneration'
1093 return 'Athena'
1094
1095

◆ _convert_event_type_bitmask()

_convert_event_type_bitmask ( value)
protected

Definition at line 1685 of file MetaReader.py.

1685def _convert_event_type_bitmask(value):
1686
1687 types = None
1688 for key in value:
1689 if key == 'bit_mask':
1690 val = value[key]
1691
1692 bitmask_length = len(val)
1693
1694 is_simulation = False
1695 is_testbeam = False
1696 is_calibration = False
1697
1698 if bitmask_length > 0: # ROOT.EventType.IS_SIMULATION
1699 is_simulation = val[0]
1700
1701 if bitmask_length > 1: # ROOT.EventType.IS_TESTBEAM
1702 is_testbeam = val[1]
1703
1704 if bitmask_length > 2: # ROOT.EventType.IS_CALIBRATION:
1705 is_calibration = val[2]
1706
1707 types = [
1708 'IS_SIMULATION' if is_simulation else 'IS_DATA',
1709 'IS_TESTBEAM' if is_testbeam else 'IS_ATLAS',
1710 'IS_CALIBRATION' if is_calibration else 'IS_PHYSICS'
1711 ]
1712
1713 value['type'] = types
1714 return value
1715
1716

◆ _convert_event_type_user_type()

_convert_event_type_user_type ( value)
protected

Definition at line 1678 of file MetaReader.py.

1678def _convert_event_type_user_type(value):
1679 if 'user_type' in value:
1680 items = value['user_type'].split('#')[3:]
1681 for i in range(0, len(items), 2):
1682 value[items[i]] = _convert_value(items[i+1])
1683 return value
1684
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179

◆ _convert_value()

_convert_value ( value,
aux = None )
protected

Definition at line 1238 of file MetaReader.py.

1238def _convert_value(value, aux = None):
1239 cl=value.__class__
1240 if hasattr(cl, '__cpp_name__'):
1241 result = regex_cppname.match(cl.__cpp_name__)
1242 if result:
1243 cpp_type = result.group(1)
1244 if cpp_type == 'vector' or cpp_type == 'std::vector':
1245 return [_convert_value(val) for val in value]
1246 elif cpp_type == 'set' or cpp_type == 'std::set':
1247 return {_convert_value(val) for val in value}
1248 elif cpp_type == 'pair' or cpp_type == 'std::pair':
1249 return _convert_value(value.first), _convert_value(value.second)
1250
1251 # elif cpp_type == 'long':
1252 # return int(value)
1253
1254 elif cpp_type == 'string' or cpp_type == 'std::string':
1255 return str(value)
1256
1257 elif cl.__cpp_name__ == "_Bit_reference":
1258 return bool(value)
1259
1260 # special case which extracts data in a better format from IOVPayloadContainer_p1 class
1261 elif cl.__cpp_name__ == 'IOVMetaDataContainer_p1':
1262 return _extract_fields_iovmdc(value)
1263
1264 elif cl.__cpp_name__ == 'IOVPayloadContainer_p1':
1265 if _gbl_mode == 'iov':
1266 return _extract_iov_detailed(value)
1267 elif _gbl_run is not None:
1268 r = _extract_iov_for_run(value, _gbl_run)
1269 if r is not None:
1270 return r
1271 # fall through to the default extraction if no IOV found for the run
1272 return _extract_fields_iov( value, range(value.m_attrIndexes.size()) )
1273
1274 elif cl.__cpp_name__ == 'ByteStreamMetadataContainer_p1':
1275 return _extract_fields_bsmd(value)
1276
1277 elif cl.__cpp_name__ == 'xAOD::EventFormat_v1':
1278 return _extract_fields_ef(value)
1279 elif cl.__cpp_name__ == 'xAOD::CutBookkeeperContainer_v1':
1280 return _extract_fields_cbk(interface=value, aux=aux)
1281 elif cl.__cpp_name__ == 'xAOD::FileMetaData_v1':
1282 return _extract_fields_fmd(interface=value, aux=aux)
1283 elif cl.__cpp_name__ == 'DataVector<xAOD::TruthMetaData_v1>':
1284 return _extract_fields_tmd(interface=value, aux=aux)
1285
1286 elif cl.__cpp_name__ == 'DataVector<xAOD::TriggerMenu_v1>' :
1287 return _extract_fields_triggermenu(interface=value, aux=aux)
1288
1289 elif cl.__cpp_name__ == 'DataVector<xAOD::TriggerMenuJson_v1>' :
1290 return _extract_fields_triggermenujson(interface=value, aux=aux)
1291
1292 elif (cl.__cpp_name__ == 'EventStreamInfo_p1' or
1293 cl.__cpp_name__ == 'EventStreamInfo_p2' or
1294 cl.__cpp_name__ == 'EventStreamInfo_p3'):
1295 return _extract_fields_esi(value)
1296
1297 elif (cl.__cpp_name__ == 'EventType_p1' or
1298 cl.__cpp_name__ == 'EventType_p3'):
1299 fields = _extract_fields(value)
1300 fields = _convert_event_type_bitmask(fields)
1301 fields = _convert_event_type_user_type(fields)
1302 return fields
1303
1304 elif regex_persistent_class.match(cl.__cpp_name__):
1305 return _extract_fields(value)
1306
1307 return value
1308
1309

◆ _extract_fields()

_extract_fields ( obj)
protected

Definition at line 1211 of file MetaReader.py.

1211def _extract_fields(obj):
1212 result = {}
1213
1214 for meth in dir(obj):
1215 if not meth.startswith('_'):
1216 if meth.startswith('m_'):
1217
1218 field_name = str(meth)[2:]
1219 field_value = getattr(obj, meth)
1220
1221 result[field_name] = _convert_value(field_value)
1222
1223 return result
1224
1225

◆ _extract_fields_bsmd()

_extract_fields_bsmd ( value)
protected
One entry per bytestream file the metadata came from.

Definition at line 1226 of file MetaReader.py.

1226def _extract_fields_bsmd(value):
1227 """One entry per bytestream file the metadata came from."""
1228 return [{'runNumber': int(md.m_runNumber),
1229 'lumiBlock': int(md.m_lumiBlock),
1230 'numEvents': int(md.m_numEvents),
1231 'guid': str(md.m_guid),
1232 'stream': str(md.m_stream),
1233 'project': str(md.m_project),
1234 'beamType': int(md.m_beamType),
1235 'beamEnergy': int(md.m_beamEnergy)} for md in value]
1236
1237

◆ _extract_fields_cbk()

_extract_fields_cbk ( interface = None,
aux = None )
protected
Extract CutBookkeeper content into dictionary

This function takes the CutBookkeeperContainer_v1 and CutBookkeeperAuxContainer_v1 objects.
It makes sure the the interface object uses the auxiliary object as store.
    Args:
        interface (CutBookkeeperContainer_v1):     the interface class
        aux       (CutBookkeeperAuxContainer_v1):  auxiliary container object
    Returns
        dict: with the cycle number and last stream

Definition at line 1486 of file MetaReader.py.

1486def _extract_fields_cbk(interface=None, aux=None):
1487 """Extract CutBookkeeper content into dictionary
1488
1489 This function takes the CutBookkeeperContainer_v1 and CutBookkeeperAuxContainer_v1 objects.
1490 It makes sure the the interface object uses the auxiliary object as store.
1491 Args:
1492 interface (CutBookkeeperContainer_v1): the interface class
1493 aux (CutBookkeeperAuxContainer_v1): auxiliary container object
1494 Returns
1495 dict: with the cycle number and last stream
1496 """
1497 if not interface or not aux:
1498 return {}
1499 interface.setStore(aux)
1500
1501 max_cycle = -1
1502 input_stream = ''
1503
1504 for cbk in interface:
1505 current_cycle = int(cbk.cycle())
1506 if current_cycle > max_cycle:
1507 max_cycle = current_cycle
1508 input_stream = str(cbk.inputStream())
1509
1510 result = {
1511 'currentCutCycle': max_cycle,
1512 'currentCutInputStream': input_stream,
1513 }
1514 return result
1515
1516

◆ _extract_fields_ef()

_extract_fields_ef ( value)
protected

Definition at line 1477 of file MetaReader.py.

1477def _extract_fields_ef(value):
1478 result = {}
1479
1480 for ef_element in value:
1481 result[ef_element.first] = ef_element.second.className()
1482
1483 return result
1484
1485

◆ _extract_fields_esi()

_extract_fields_esi ( value)
protected

Definition at line 1451 of file MetaReader.py.

1451def _extract_fields_esi(value):
1452 result = {}
1453
1454 result['eventTypes'] = []
1455 for eventType in value.m_eventTypes:
1456 result['eventTypes'].append(_convert_value(eventType))
1457
1458 result['numberOfEvents'] = value.m_numberOfEvents
1459 result['runNumbers'] = list(value.m_runNumbers)
1460 result['lumiBlockNumbers'] = list(value.m_lumiBlockNumbers)
1461 result['processingTags'] = [str(v) for v in value.m_processingTags]
1462 result['itemList'] = []
1463
1464 # Get the class name in the repository with CLID <clid>
1465 from CLIDComps.clidGenerator import clidGenerator
1466 cgen = clidGenerator("")
1467 for clid, sgkey in value.m_itemList:
1468 if isinstance(sgkey, bytes):
1469 sgkey = sgkey.decode()
1470 else:
1471 sgkey = str(sgkey)
1472 result['itemList'].append((cgen.getNameFromClid(clid), sgkey))
1473
1474 return result
1475
1476

◆ _extract_fields_fmd()

_extract_fields_fmd ( interface = None,
aux = None )
protected
Turn static FileMetaData content into dictionary

This function takes the FileMetaData_v1 and FileMetaDataAuxInfo_v1 objects.
It makes sure the the interface object uses the auxiliary object as store.
Next the two static variables of FileMetaDataAuxInfo_v1 are retrieved and
added to the dictionary that is returned.
    Args:
        interface (FileMetaData_v1):        the interface class
        aux       (FileMetaDataAuxInfo_v1): auxiliary container object
    Returns
        dict: with the production release and dataType

Definition at line 1517 of file MetaReader.py.

1517def _extract_fields_fmd(interface=None, aux=None):
1518 """Turn static FileMetaData content into dictionary
1519
1520 This function takes the FileMetaData_v1 and FileMetaDataAuxInfo_v1 objects.
1521 It makes sure the the interface object uses the auxiliary object as store.
1522 Next the two static variables of FileMetaDataAuxInfo_v1 are retrieved and
1523 added to the dictionary that is returned.
1524 Args:
1525 interface (FileMetaData_v1): the interface class
1526 aux (FileMetaDataAuxInfo_v1): auxiliary container object
1527 Returns
1528 dict: with the production release and dataType
1529 """
1530 import ROOT
1531 if not interface or not aux:
1532 return {}
1533 interface.setStore(aux)
1534 metaContent = {
1535 "productionRelease": ROOT.std.string(),
1536 "dataType": ROOT.std.string(),
1537 "runNumbers": ROOT.std.vector('unsigned int')(),
1538 "lumiBlocks": ROOT.std.vector('unsigned int')(),
1539 }
1540 # Note: using this for dynamic attributes returns empty content
1541 for k, v in metaContent.items():
1542 try:
1543 interface.value(getattr(interface, k), v)
1544 except AttributeError:
1545 interface.value(k, v)
1546 # Now return python objects
1547 result = {k: str(v) for k, v in metaContent.items() if type(v) is ROOT.std.string}
1548 result.update({k: list(v) for k, v in metaContent.items() if type(v) is ROOT.std.vector('unsigned int')})
1549 return result
1550
1551

◆ _extract_fields_iov()

_extract_fields_iov ( iov_container,
idx_range )
protected

Definition at line 1363 of file MetaReader.py.

1363def _extract_fields_iov( iov_container, idx_range ):
1364 result = {}
1365 for idx in idx_range:
1366 attr_idx = iov_container.m_attrIndexes[idx]
1367 name_idx = attr_idx.nameIndex()
1368 attr_name = iov_container.m_attrName[name_idx]
1369 attr_value = _get_attribute_val(iov_container, attr_name, attr_idx)
1370
1371 if attr_name not in result:
1372 result[attr_name] = [attr_value]
1373 else:
1374 result[attr_name].append(attr_value)
1375
1376 max_element_count = 0
1377 for content in result.values():
1378 if len(content) > max_element_count:
1379 max_element_count = len(content)
1380
1381 if max_element_count <= 1:
1382 for name, content in result.items():
1383 if len(content) > 0:
1384 result[name] = content[0]
1385 else:
1386 result[name] = None
1387
1388 return result
1389
1390

◆ _extract_fields_iovmdc()

_extract_fields_iovmdc ( value)
protected

Definition at line 1447 of file MetaReader.py.

1447def _extract_fields_iovmdc(value):
1448 return _convert_value(value.m_payload)
1449
1450

◆ _extract_fields_tmd()

_extract_fields_tmd ( interface = None,
aux = None )
protected

Definition at line 1552 of file MetaReader.py.

1552def _extract_fields_tmd(interface=None, aux=None):
1553 import ROOT
1554 BadAuxVarException = ROOT.SG.ExcBadAuxVar
1555 """Extract TruthMetaData content into dictionary
1556
1557 This function takes the TruthMetaDataContainer_v1 and TruthMetaDataAuxContainer_v1 objects.
1558 It makes sure the the interface object uses the auxiliary object as store.
1559 Args:
1560 interface (TruthMetaDataContainer_v1): the interface class
1561 aux (TruthMetaDataAuxContainer_v1): auxiliary container object
1562 Returns
1563 dict
1564 """
1565 if not interface or not aux:
1566 return {}
1567 interface.setStore(aux)
1568
1569 # return the first as we do not really expect more than one
1570 result = {}
1571 for tmd in interface:
1572 result['mcChannelNumber'] = tmd.mcChannelNumber()
1573
1574 try:
1575 result['weightNames'] = [str(v) for v in tmd.weightNames()]
1576 except BadAuxVarException:
1577 result['weightNames'] = []
1578
1579 try:
1580 result['lhefGenerator'] = str(tmd.lhefGenerator())
1581 except BadAuxVarException:
1582 result['lhefGenerator'] = ''
1583
1584 try:
1585 result['generators'] = str(tmd.generators())
1586 except BadAuxVarException:
1587 result['generators'] = ''
1588
1589 try:
1590 result['evgenProcess'] = str(tmd.evgenProcess())
1591 except BadAuxVarException:
1592 result['evgenProcess'] = ''
1593
1594 try:
1595 result['evgenTune'] = str(tmd.evgenTune())
1596 except BadAuxVarException:
1597 result['evgenTune'] = ''
1598
1599 try:
1600 result['hadronizationModel'] = str(tmd.hadronizationModel())
1601 except BadAuxVarException:
1602 result['hadronizationModel'] = ''
1603
1604 try:
1605 result['partonShowerModel'] = str(tmd.partonShowerModel())
1606 except BadAuxVarException:
1607 result['partonShowerModel'] = ''
1608
1609 try:
1610 result['hardPDF'] = str(tmd.hardPDF())
1611 except BadAuxVarException:
1612 result['hardPDF'] = ''
1613
1614 try:
1615 result['softPDF'] = str(tmd.softPDF())
1616 except BadAuxVarException:
1617 result['softPDF'] = ''
1618
1619 return result
1620
1621
1622""" Note: Deprecated. Legacy support for Run 2 AODs produced in release 21 or in release 22 prior to April 2021
1623"""

◆ _extract_fields_triggermenu()

_extract_fields_triggermenu ( interface,
aux )
protected

Definition at line 1624 of file MetaReader.py.

1624def _extract_fields_triggermenu(interface, aux):
1625 if aux is None:
1626 return {}
1627
1628 L1Items = []
1629 HLTChains = []
1630
1631 try:
1632 interface.setStore( aux )
1633 if interface.size() > 0:
1634 # We make the assumption that the first stored SMK is
1635 # representative of all events in the input collection.
1636 firstMenu = interface.at(0)
1637 L1Items = [ _convert_value(item) for item in firstMenu.itemNames() ]
1638 HLTChains = [ _convert_value(chain) for chain in firstMenu.chainNames() ]
1639 except Exception as err: # noqa: F841
1640 msg.warning('Problem reading xAOD::TriggerMenu:')
1641
1642 result = {}
1643 result['L1Items'] = L1Items
1644 result['HLTChains'] = HLTChains
1645
1646 return result
1647

◆ _extract_fields_triggermenujson()

_extract_fields_triggermenujson ( interface,
aux )
protected

Definition at line 1648 of file MetaReader.py.

1648def _extract_fields_triggermenujson(interface, aux):
1649 result = {}
1650
1651 try:
1652 interface.setStore( aux )
1653 if interface.size() > 0:
1654 # We make the assumption that the first stored SMK is
1655 # representative of all events in the input collection.
1656 firstMenu = interface.at(0)
1657 import json
1658 decoded = json.loads(firstMenu.payload())
1659 result['RAWTriggerMenuJson'] = firstMenu.payload()
1660 result['name'] = firstMenu.name()
1661 result['dbkey'] = firstMenu.key()
1662 if decoded['filetype'] == 'hltmenu':
1663 result['HLTChains'] = [ _convert_value(chain) for chain in decoded['chains'] ]
1664 elif decoded['filetype'] == 'l1menu':
1665 result['L1Items'] = [ _convert_value(item) for item in decoded['items'] ]
1666 elif decoded['filetype'] in ['bunchgroupset', 'hltprescale', 'l1prescale', 'hltmonitoringsummary']:
1667 return result
1668
1669 else:
1670 msg.warning('Got an xAOD::TriggerMenuJson called {0} but only expecting hltmenu or l1menu'.format(decoded['filetype']))
1671 return {}
1672
1673 except Exception as err: # noqa: F841
1674 msg.warning('Problem reading xAOD::TriggerMenuJson')
1675
1676 return result
1677

◆ _extract_iov_detailed()

_extract_iov_detailed ( iov_container)
protected

Definition at line 1420 of file MetaReader.py.

1420def _extract_iov_detailed(iov_container):
1421 def iovtostr(t):
1422 # break iov time into high and low halves (run number usually in the higher half)
1423 return "({h}:{l})".format(h=t>>32, l=t&(2**32-1))
1424
1425 def extract_list_collection(iov_container, listCollection ):
1426 result = {}
1427 ln = 0
1428 for list in listCollection.m_attrLists:
1429 ln = ln + 1
1430 lname = 'List {ln}: iov=[{s} ,{e}]; Channel#={ch}'.format(
1431 ln=ln, s=iovtostr(list.m_range.m_start),
1432 e=iovtostr(list.m_range.m_stop),
1433 ch=list.m_channelNumber )
1434 result[ lname ] = _extract_fields_iov( iov_container, range(list.m_firstIndex, list.m_lastIndex) )
1435 return result
1436
1437 result = {}
1438 pn = 0
1439 for listCollection in iov_container.m_payloadVec:
1440 pn = pn + 1
1441 pname = 'IOV range {n}: [{s}, {e}]'.format(n=pn, s=iovtostr(listCollection.m_start),
1442 e=iovtostr(listCollection.m_stop))
1443 result[ pname ] = extract_list_collection(iov_container, listCollection )
1444 return result
1445
1446

◆ _extract_iov_for_run()

_extract_iov_for_run ( iov_container,
run )
protected

Definition at line 1391 of file MetaReader.py.

1391def _extract_iov_for_run(iov_container, run):
1392 def extract_payload(iov_container, payload):
1393 result = {}
1394 for attrList in payload.m_attrLists:
1395 r = _extract_fields_iov( iov_container, range(attrList.m_firstIndex, attrList.m_lastIndex) )
1396 for name, content in r.items():
1397 if name not in result:
1398 result[name] = [content]
1399 elif content not in result[name]:
1400 result[name].append(content)
1401 # turn single element lists into single values
1402 for name, content in result.items():
1403 if len(content) == 1:
1404 result[name] = content[0]
1405 elif len(content) == 0:
1406 # to be consistent with the old code
1407 result[name] = None
1408 return result
1409
1410 for payload in iov_container.m_payloadVec:
1411 if run >= payload.m_start>>32 and run < payload.m_stop>>32:
1412 return extract_payload(iov_container, payload)
1413 # IOV for the requested run not found
1414 if len(iov_container.m_payloadVec) > 0:
1415 # print a warning only if there was actually some payload in the container
1416 msg.warning('No IOV found for run %d', run)
1417 return None
1418
1419

◆ _get_attribute_val()

_get_attribute_val ( iov_container,
attr_name,
attr_idx )
protected

Definition at line 1310 of file MetaReader.py.

1310def _get_attribute_val(iov_container, attr_name, attr_idx):
1311 type_idx = attr_idx.typeIndex()
1312 obj_idx = attr_idx.objIndex()
1313
1314 attr_value = None
1315
1316 if type_idx == 0:
1317 attr_value = bool(iov_container.m_bool[obj_idx])
1318 elif type_idx == 1:
1319 attr_value = int(iov_container.m_char[obj_idx])
1320 elif type_idx == 2:
1321 attr_value = int(iov_container.m_unsignedChar[obj_idx])
1322 elif type_idx == 3:
1323 attr_value = int(iov_container.m_short[obj_idx])
1324 elif type_idx == 4:
1325 attr_value = int(iov_container.m_unsignedShort[obj_idx])
1326 elif type_idx == 5:
1327 attr_value = int(iov_container.m_int[obj_idx])
1328 elif type_idx == 6:
1329 attr_value = int(iov_container.m_unsignedInt[obj_idx])
1330 elif type_idx == 7:
1331 attr_value = int(iov_container.m_long[obj_idx])
1332 elif type_idx == 8:
1333 attr_value = int(iov_container.m_unsignedLong[obj_idx])
1334 elif type_idx == 9:
1335 attr_value = int(iov_container.m_longLong[obj_idx])
1336 elif type_idx == 10:
1337 attr_value = int(iov_container.m_unsignedLongLong[obj_idx])
1338 elif type_idx == 11:
1339 attr_value = float(iov_container.m_float[obj_idx])
1340 elif type_idx == 12:
1341 attr_value = float(iov_container.m_double[obj_idx])
1342 elif type_idx == 13:
1343 # skipping this type because is file IOVPayloadContainer_p1.h (line 120) is commented and not considered
1344 pass
1345 elif type_idx == 14:
1346 attr_value = str(iov_container.m_string[obj_idx])
1347 # Cleaning class name from value
1348 if attr_value.startswith('IOVMetaDataContainer_p1_'):
1349 attr_value = attr_value.replace('IOVMetaDataContainer_p1_', '')
1350 if attr_value.startswith('_'):
1351 attr_value = attr_value.replace('_', '/')
1352 # Now it is clean
1353 elif type_idx == 15:
1354 attr_value = int(iov_container.m_date[obj_idx])
1355 elif type_idx == 16:
1356 attr_value = int(iov_container.m_timeStamp[obj_idx])
1357 else:
1358 raise ValueError('Unknown type id {0} for attribute {1}'.format(type_idx, attr_name))
1359
1360 return attr_value
1361
1362

◆ _get_entry_value()

_get_entry_value ( entry,
field_name,
type_name )
protected
Get the value of a field from a loaded RNTuple entry.

Indexing the entry instantiates the typed REntry::GetPtr<T>, which fails for
some classes (e.g. DataVector<xAOD::TriggerMenu_v1> in AnalysisBase), so
classes are retrieved type-erased and bound to their type by name instead.

Definition at line 1167 of file MetaReader.py.

1167def _get_entry_value(entry, field_name, type_name):
1168 """Get the value of a field from a loaded RNTuple entry.
1169
1170 Indexing the entry instantiates the typed REntry::GetPtr<T>, which fails for
1171 some classes (e.g. DataVector<xAOD::TriggerMenu_v1> in AnalysisBase), so
1172 classes are retrieved type-erased and bound to their type by name instead.
1173 """
1174 import ROOT
1175
1176 if not ROOT.TClass.GetClass(type_name):
1177 return entry[field_name]
1178 return ROOT.bind_object(entry._GetPtr["void"](field_name).get(), type_name)
1179
1180
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132

◆ _get_pfn()

_get_pfn ( filename)
protected
Extract the actual filename if LFN or PFN notation is used

Definition at line 1096 of file MetaReader.py.

1096def _get_pfn(filename):
1097 """
1098 Extract the actual filename if LFN or PFN notation is used
1099 """
1100 pfx = filename[0:4]
1101 if pfx == 'PFN:':
1102 return filename[4:]
1103 if pfx == 'LFN:':
1104 import subprocess, os
1105 os.environ['POOL_OUTMSG_LEVEL'] = 'Error'
1106 output = subprocess.check_output(['FClistPFN','-l',filename[4:]],text=True).split('\n')
1107 if len(output) == 2:
1108 return output[0]
1109 msg.error( 'FClistPFN({0}) returned unexpected number of lines:'.format(filename) )
1110 msg.error( '\n'.join(output) )
1111 return filename
1112
1113

◆ _read_guid()

_read_guid ( filename)
protected
Extracts the "guid" (Globally Unique Identifier) in POOL files and Grid catalogs) value from a POOL file.
:param filename: the input file
:return: the guid value, None if unavailable

Definition at line 1114 of file MetaReader.py.

1114def _read_guid(filename):
1115 """
1116 Extracts the "guid" (Globally Unique Identifier) in POOL files and Grid catalogs) value from a POOL file.
1117 :param filename: the input file
1118 :return: the guid value, None if unavailable
1119 """
1120 import ROOT
1121 root_file = ROOT.TFile.Open( _get_pfn(filename) )
1122 params = root_file.Get('##Params')
1123 if not params:
1124 return
1125 if not isinstance(params, ROOT.TTree) and not isinstance(params, ROOT.RNTuple) and not isinstance(params, ROOT.TDirectory):
1126 raise NotImplementedError(f"Cannot extract GUID from object {params!r} of type {type(params)!r}")
1127
1128 regex = re.compile(r'\‍[NAME=(\w+)\‍]\‍[VALUE=(.*)\‍]', re.ASCII)
1129 fid = None
1130
1131 if isinstance(params, ROOT.TTree):
1132 for entry in params:
1133 param = entry.GetLeaf('db_string').GetValueString()
1134 result = regex.match(param)
1135 if result and result.group(1) == 'FID' :
1136 # don't exit yet, it's the last FID entry that counts
1137 fid = result.group(2)
1138 elif isinstance(params, ROOT.RNTuple):
1139 reader = ROOT.RNTupleReader.Open(params)
1140 try:
1141 entry = reader.CreateEntry()
1142 except AttributeError:
1143 entry = reader.GetModel().CreateEntry()
1144 for idx in range(reader.GetNEntries()):
1145 reader.LoadEntry(idx, entry)
1146 try:
1147 result = regex.match(str(entry['db_string']))
1148 except (AttributeError, TypeError) as err:
1149 # Early RNTuple implementation doesn't allow reading
1150 # strings on the python side, might be triggering it...
1151 msg.error(f"Cannot read FID from ##Params in RNTuple w/ ROOT error: {err}")
1152 return None
1153 if result and result.group(1) == 'FID' :
1154 # don't exit yet, it's the last FID entry that counts
1155 fid = result.group(2)
1156 elif isinstance(params, ROOT.TDirectory):
1157 for key in params.GetListOfKeys():
1158 param = params.Get(key.GetName())
1159 result = regex.match(str(param))
1160 if result and result.group(1) == 'FID' :
1161 # don't exit yet, it's the last FID entry that counts
1162 fid = result.group(2)
1163
1164 return fid
1165
1166

◆ _rntuple_type_to_class_name()

_rntuple_type_to_class_name ( type_name)
protected
Convert an RNTuple type name to the class name of the equivalent TTree branch.

RNTuple uses the canonical type names (e.g. std::vector<std::int32_t>), while
TTree branches report the ROOT class names (e.g. vector<int>). Fundamental types
are stored as plain leaves in a TTree, which do not have a class name.

Definition at line 1181 of file MetaReader.py.

1181def _rntuple_type_to_class_name(type_name):
1182 """Convert an RNTuple type name to the class name of the equivalent TTree branch.
1183
1184 RNTuple uses the canonical type names (e.g. std::vector<std::int32_t>), while
1185 TTree branches report the ROOT class names (e.g. vector<int>). Fundamental types
1186 are stored as plain leaves in a TTree, which do not have a class name.
1187 """
1188 if type_name in _rntuple_fundamental_types:
1189 return ''
1190 type_name = re.sub(r'std::u?int(?:8|16|32|64)_t',
1191 lambda m: _rntuple_integer_types[m.group(0)], type_name)
1192 type_name = type_name.replace('std::', '')
1193 # ROOT class names separate consecutive closing brackets with a space
1194 while '>>' in type_name:
1195 type_name = type_name.replace('>>', '> >')
1196 return type_name
1197
1198

◆ convert_itemList()

convert_itemList ( metadata,
layout )
This function will rearrange the itemList values to match the format of 'eventdata_items', 'eventdata_itemsList'
or 'eventdata_itemsDic' generated with the legacy file peeker tool
:param metadata: a dictionary obtained using read_metadata method.
                 The mode for read_metadata must be 'peeker of 'full'
:param layout: the mode in which the data will be converted:
            * for 'eventdata_items' use: layout= None
            * for 'eventdata_itemsList' use: layout= '#join'
            * for 'eventdata_itemsDic' use: layout= 'dict'

Definition at line 1948 of file MetaReader.py.

1948def convert_itemList(metadata, layout):
1949 """
1950 This function will rearrange the itemList values to match the format of 'eventdata_items', 'eventdata_itemsList'
1951 or 'eventdata_itemsDic' generated with the legacy file peeker tool
1952 :param metadata: a dictionary obtained using read_metadata method.
1953 The mode for read_metadata must be 'peeker of 'full'
1954 :param layout: the mode in which the data will be converted:
1955 * for 'eventdata_items' use: layout= None
1956 * for 'eventdata_itemsList' use: layout= '#join'
1957 * for 'eventdata_itemsDic' use: layout= 'dict'
1958 """
1959
1960 # Find the itemsList:
1961 item_list = None
1962
1963 if 'itemList' in metadata:
1964 item_list = metadata['itemList']
1965 else:
1966
1967 current_key = None
1968
1969 for key in metadata:
1970 if 'metadata_items' in metadata and key in metadata['metadata_items'] and metadata['metadata_items'][key] == 'EventStreamInfo_p3':
1971 current_key = key
1972 break
1973 if current_key is not None:
1974 item_list = metadata[current_key]['itemList']
1975
1976 if item_list is not None:
1977
1978 if layout is None:
1979 return item_list
1980
1981 elif layout == '#join':
1982 return [k + '#' + v for k, v in item_list if k]
1983
1984
1985 elif layout == 'dict':
1986 from collections import defaultdict
1987 dic = defaultdict(list)
1988
1989 for k, v in item_list:
1990 dic[k].append(v)
1991
1992 return dict(dic)
1993
1994

◆ dataheader_nentries()

dataheader_nentries ( infile)
Extract number of entries from DataHeader.

infile  ROOT TFile object or filename string
return  Number of entries as returned by DataHeader object in infile,
        None in absence of DataHeader object

Definition at line 1995 of file MetaReader.py.

1995def dataheader_nentries(infile):
1996 """Extract number of entries from DataHeader.
1997
1998 infile ROOT TFile object or filename string
1999 return Number of entries as returned by DataHeader object in infile,
2000 None in absence of DataHeader object
2001 """
2002 import ROOT
2003 from PyUtils.PoolFile import PoolOpts
2004 if not isinstance(infile, ROOT.TFile):
2005 infile = ROOT.TFile.Open(infile)
2006
2007 # with the canonical naming scheme the DataHeader is stored in the EventData RNTuple
2008 for name in (PoolOpts.TTreeNames.DataHeader, PoolOpts.RNTupleNames.DataHeader,
2009 PoolOpts.RNTupleNames.EventData):
2010 obj = infile.Get(name)
2011 msg.debug(f"dataheader_nentries: {name=}, {obj=}, {type(obj)=}")
2012 if not obj:
2013 continue
2014 if isinstance(obj, ROOT.TTree):
2015 return obj.GetEntriesFast()
2016 else:
2017 # check early to avoid scary ROOT read errors
2018 if ROOT.gROOT.GetVersionInt() < 63100:
2019 raise RuntimeError("ROOT ver. 6.31/01 or greater needed to read RNTuple files")
2020 if isRNTuple(obj):
2021 return ROOT.RNTupleReader.Open(obj).GetNEntries()
2022 else:
2023 raise NotImplementedError(f"Keys of type {type(obj)!r} not supported")
2024

◆ denormalize_metadata_types()

denormalize_metadata_types ( metadata_dict)
Convert canonical/C++ STL types in the metadata_items dictionary back to their
ROOT equivalents for backward compatibility.
- 'float' => 'Float_t'
- 'char' => 'Char_t'
- 'std::string' => 'string'
- 'xAOD::FileMetaData_v1' => 'FileMetaData'
- 'xAOD::FileMetaDataAuxInfo_v1' => 'FileMetaDataAux'
- template types, e.g. 'std::vector<std::uint32_t>' => 'vector<unsigned int>'
(add more as needed)

Definition at line 2100 of file MetaReader.py.

2100def denormalize_metadata_types(metadata_dict):
2101 """
2102 Convert canonical/C++ STL types in the metadata_items dictionary back to their
2103 ROOT equivalents for backward compatibility.
2104 - 'float' => 'Float_t'
2105 - 'char' => 'Char_t'
2106 - 'std::string' => 'string'
2107 - 'xAOD::FileMetaData_v1' => 'FileMetaData'
2108 - 'xAOD::FileMetaDataAuxInfo_v1' => 'FileMetaDataAux'
2109 - template types, e.g. 'std::vector<std::uint32_t>' => 'vector<unsigned int>'
2110 (add more as needed)
2111 """
2112 type_map = {
2113 "float": "Float_t",
2114 "char": "Char_t",
2115 "std::string": "string",
2116 "std::uint32_t": "UInt_t",
2117 "xAOD::FileMetaData_v1": "FileMetaData",
2118 }
2119 denormalized = {}
2120 for k, v in metadata_dict.items():
2121 new_v = v
2122 for old, new in type_map.items():
2123 if new_v == old:
2124 new_v = new
2125 elif new_v.endswith("." + old):
2126 new_v = new_v.rsplit(".", 1)[0] + "." + new
2127 if "<" in new_v:
2128 new_v = _rntuple_type_to_class_name(new_v)
2129 denormalized[k] = new_v
2130 return denormalized
2131
2132

◆ get_meta_filter()

dict get_meta_filter ( mode = "lite",
meta_key_filter = None )
Return a dictionary of metadata filters based on the mode and
optional meta_key_filter.

Definition at line 2025 of file MetaReader.py.

2025def get_meta_filter(mode="lite", meta_key_filter=None) -> dict:
2026 """Return a dictionary of metadata filters based on the mode and
2027 optional meta_key_filter.
2028 """
2029
2030 if meta_key_filter is None:
2031 meta_key_filter = []
2032
2033 # create a container for the list of filters used for the lite version
2034 meta_filter = {}
2035
2036 # set the filters for name
2037 if mode == 'lite':
2038 if isGaudiEnv():
2039 meta_filter = {
2040 '/TagInfo': 'IOVMetaDataContainer_p1',
2041 'IOVMetaDataContainer_p1__TagInfo': 'IOVMetaDataContainer_p1',
2042 '*': 'EventStreamInfo_p*'
2043 }
2044 else:
2045 meta_filter = {
2046 'FileMetaData': '*',
2047 'FileMetaDataAux.': 'xAOD::FileMetaDataAuxInfo_v1',
2048 }
2049
2050 # set the filters for name
2051 if mode == 'peeker':
2052 meta_filter.update({
2053 'TriggerMenu': 'DataVector<xAOD::TriggerMenu_v1>', # R2 trigger metadata format AOD (deprecated)
2054 'TriggerMenuAux.': 'xAOD::TriggerMenuAuxContainer_v1',
2055 'DataVector<xAOD::TriggerMenu_v1>_TriggerMenu': 'DataVector<xAOD::TriggerMenu_v1>', # R2 trigger metadata format ESD (deprecated)
2056 'xAOD::TriggerMenuAuxContainer_v1_TriggerMenuAux.': 'xAOD::TriggerMenuAuxContainer_v1',
2057 'TriggerMenuJson_HLT': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format AOD
2058 'TriggerMenuJson_HLTAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2059 'TriggerMenuJson_HLTMonitoring': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format AOD
2060 'TriggerMenuJson_HLTMonitoringAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2061 'TriggerMenuJson_HLTPS': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format AOD
2062 'TriggerMenuJson_HLTPSAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2063 'TriggerMenuJson_L1': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format AOD
2064 'TriggerMenuJson_L1Aux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2065 'TriggerMenuJson_L1PS': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format AOD
2066 'TriggerMenuJson_L1PSAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2067 'CutBookkeepers': 'xAOD::CutBookkeeperContainer_v1',
2068 'CutBookkeepersAux.': 'xAOD::CutBookkeeperAuxContainer_v1',
2069 'FileMetaData': '*',
2070 'FileMetaDataAux.': 'xAOD::FileMetaDataAuxInfo_v1',
2071 'TruthMetaData': '*',
2072 'TruthMetaDataAux.': 'xAOD::TruthMetaDataAuxContainer_v1',
2073 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format ESD
2074 'xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_HLTAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2075 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTMonitoring': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format ESD
2076 'xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_HLTMonitoringAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2077 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTPS': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format ESD
2078 'xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_HLTPSAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2079 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format ESD
2080 'xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_L1Aux.': 'xAOD::TriggerMenuJsonAuxContainer_v1',
2081 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1PS': 'DataVector<xAOD::TriggerMenuJson_v1>', # R3 trigger metadata format ESD
2082 'xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_L1PSAux.': 'xAOD::TriggerMenuJsonAuxContainer_v1'
2083 })
2084
2085 if isGaudiEnv():
2086 meta_filter.update({
2087 '/TagInfo': 'IOVMetaDataContainer_p1',
2088 'IOVMetaDataContainer_p1__TagInfo': 'IOVMetaDataContainer_p1',
2089 '/Simulation/Parameters': 'IOVMetaDataContainer_p1',
2090 '/Digitization/Parameters': 'IOVMetaDataContainer_p1',
2091 '/EXT/DCS/MAGNETS/SENSORDATA': 'IOVMetaDataContainer_p1',
2092 '*': 'EventStreamInfo_p*'
2093 })
2094
2095 if (mode == 'full' or mode == 'iov') and meta_key_filter:
2096 meta_filter = {f: '*' for f in meta_key_filter}
2097
2098 return meta_filter
2099

◆ ignore_missing_dictionary_warnings()

ignore_missing_dictionary_warnings ( func)
Ignore ROOT warnings about missing class dictionaries while func runs.

Definition at line 85 of file MetaReader.py.

85def ignore_missing_dictionary_warnings(func):
86 """Ignore ROOT warnings about missing class dictionaries while func runs."""
87
88 @functools.wraps(func)
89 def wrapper(*args, **kwargs):
90 with warnings.catch_warnings():
91 warnings.filterwarnings(
92 "ignore",
93 message=r".*no dictionary for class",
94 category=RuntimeWarning,
95 )
96 return func(*args, **kwargs)
97
98 return wrapper
99
100
101@ignore_missing_dictionary_warnings

◆ make_lite()

make_lite ( meta_dict)

Definition at line 1717 of file MetaReader.py.

1717def make_lite(meta_dict):
1718 for filename, file_content in meta_dict.items():
1719 for key in file_content:
1720 if key in meta_dict[filename]['metadata_items'] and regexEventStreamInfo.match(meta_dict[filename]['metadata_items'][key]):
1721 for item in list(meta_dict[filename][key]):
1722 if item not in lite_primary_keys_to_keep:
1723 meta_dict[filename][key].pop(item)
1724
1725 if '/TagInfo' in file_content:
1726
1727
1728 for item in list(meta_dict[filename]['/TagInfo']):
1729 if item not in lite_TagInfo_keys_to_keep:
1730 meta_dict[filename]['/TagInfo'].pop(item)
1731 return meta_dict
1732
1733

◆ make_peeker()

make_peeker ( meta_dict)

Definition at line 1734 of file MetaReader.py.

1734def make_peeker(meta_dict):
1735 for filename, file_content in meta_dict.items():
1736 for key in file_content:
1737 if key in meta_dict[filename]['metadata_items'] and regexEventStreamInfo.match(meta_dict[filename]['metadata_items'][key]):
1738 keys_to_keep = [
1739 'lumiBlockNumbers',
1740 'runNumbers',
1741 'mc_event_number',
1742 'mc_channel_number',
1743 'eventTypes',
1744 'processingTags',
1745 'itemList'
1746 ]
1747 for item in list(meta_dict[filename][key]):
1748 if item not in keys_to_keep:
1749 meta_dict[filename][key].pop(item)
1750
1751 if '/TagInfo' in file_content:
1752 keys_to_keep = [
1753 'beam_energy',
1754 'beam_type',
1755 'GeoAtlas',
1756 'IOVDbGlobalTag',
1757 'AODFixVersion',
1758 'AMITag',
1759 'project_name',
1760 'triggerStreamOfFile',
1761 'AtlasRelease',
1762 'specialConfiguration',
1763 'mc_campaign',
1764 'hepmc_version',
1765 'generators',
1766 'keywords',
1767 'data_year',
1768 ]
1769 for item in list(meta_dict[filename]['/TagInfo']):
1770 if item not in keys_to_keep:
1771 meta_dict[filename]['/TagInfo'].pop(item)
1772
1773 if '/Simulation/Parameters' in file_content:
1774 keys_to_keep = [
1775 'G4Version',
1776 'TruthStrategy',
1777 'SimBarcodeOffset',
1778 'RegenerationIncrement',
1779 'TRTRangeCut',
1780 'SimulationFlavour',
1781 'Simulator',
1782 'PhysicsList',
1783 'SimulatedDetectors',
1784 'IsDataOverlay',
1785 ]
1786 for item in list(meta_dict[filename]['/Simulation/Parameters']):
1787 if item not in keys_to_keep:
1788 meta_dict[filename]['/Simulation/Parameters'].pop(item)
1789
1790 if '/Digitization/Parameters' in file_content:
1791 keys_to_keep = [
1792 'numberOfCollisions',
1793 'intraTrainBunchSpacing',
1794 'BeamIntensityPattern'
1795 'physicsList',
1796 'digiSteeringConf',
1797 'pileUp',
1798 'DigitizedDetectors',
1799 ]
1800 for item in list(meta_dict[filename]['/Digitization/Parameters']):
1801 if item not in keys_to_keep:
1802 meta_dict[filename]['/Digitization/Parameters'].pop(item)
1803
1804 if 'CutBookkeepers' in file_content:
1805 keys_to_keep = [
1806 'currentCutCycle',
1807 'currentCutInputStream',
1808 ]
1809 for item in list(meta_dict[filename]['CutBookkeepers']):
1810 if item not in keys_to_keep:
1811 meta_dict[filename]['CutBookkeepers'].pop(item)
1812
1813 if 'TruthMetaData' in file_content:
1814 keys_to_keep = [
1815 'mcChannelNumber',
1816 'weightNames',
1817 ]
1818 for item in list(meta_dict[filename]['TruthMetaData']):
1819 if item not in keys_to_keep:
1820 meta_dict[filename]['TruthMetaData'].pop(item)
1821
1822 return meta_dict
1823
1824

◆ promote_keys()

promote_keys ( meta_dict,
mode )

Definition at line 1825 of file MetaReader.py.

1825def promote_keys(meta_dict, mode):
1826 for filename, file_content in meta_dict.items():
1827 md = meta_dict[filename]
1828 for key in file_content:
1829 if key in md['metadata_items'] and regexEventStreamInfo.match(md['metadata_items'][key]):
1830 md.update(md[key])
1831
1832 if 'eventTypes' in md and len(md['eventTypes']):
1833 et = md['eventTypes'][0]
1834 md['mc_event_number'] = et.get('mc_event_number', md['runNumbers'][0])
1835 if 'mc_channel_number' in et:
1836 md['mc_channel_number'] = et.get('mc_channel_number', None)
1837 md['eventTypes'] = et['type']
1838
1839 # For very old files
1840 if 'GeoAtlas' in et:
1841 md['GeoAtlas'] = et.get('GeoAtlas', None)
1842 if 'IOVDbGlobalTag' in et:
1843 md['IOVDbGlobalTag'] = et.get('IOVDbGlobalTag', None)
1844
1845 if 'lumiBlockNumbers' in md[key]:
1846 md['lumiBlockNumbers'] = md[key]['lumiBlockNumbers']
1847
1848 if 'processingTags' in md[key]:
1849 md['processingTags'] = md[key]['processingTags']
1850
1851 meta_dict[filename].pop(key)
1852 break
1853
1854 if not isGaudiEnv() and key in md['metadata_items'] and 'FileMetaData' in key:
1855 if 'beamType' in md[key]:
1856 md['beam_type'] = md[key]['beamType']
1857
1858 if 'runNumbers' in md[key]:
1859 md['runNumbers'] = md[key]['runNumbers']
1860
1861 if 'mcProcID' in md[key]:
1862 md['mc_channel_number'] = int(md[key]['mcProcID'])
1863
1864 if 'mcCampaign' in md[key]:
1865 md['mc_campaign'] = md[key]['mcCampaign']
1866
1867 if 'dataYear' in md[key]:
1868 md['data_year'] = int(md[key]['dataYear'])
1869
1870 if 'lumiBlocks' in md[key]:
1871 md['lumiBlockNumbers'] = md[key]['lumiBlocks']
1872
1873 if mode == 'peeker' and 'amiTag' in md[key]:
1874 md['AMITag'] = md[key]['amiTag']
1875
1876 if 'beamEnergy' in md[key]:
1877 md['beam_energy'] = int(md[key]['beamEnergy'])
1878
1879 if 'geometryVersion' in md[key]:
1880 md['GeoAtlas'] = md[key]['geometryVersion']
1881
1882 if 'AODFixVersion' in md[key]:
1883 md['AODFixVersion'] = md[key]['AODFixVersion']
1884
1885 # EventType checks
1886 md['eventTypes'] = []
1887 if mode == 'peeker' and 'simFlavour' in md[key]:
1888 md['SimulationFlavour'] = md[key]['simFlavour']
1889
1890 if mode == 'peeker' and 'isDataOverlay' in md[key]:
1891 md['IsDataOverlay'] = md[key]['isDataOverlay']
1892
1893 if 'dataType' in md[key]:
1894 md['processingTags'] = [md[key]['dataType']]
1895
1896 if (
1897 ('simFlavour' in md[key] and ('FullG4' in md[key]['simFlavour'] or 'ATLFAST' in md[key]['simFlavour']))
1898 or 'DAOD_TRUTH' in md[key]['dataType']
1899 ):
1900 md['eventTypes'].append('IS_SIMULATION')
1901 else:
1902 md['eventTypes'].append('IS_DATA')
1903
1904 if (
1905 'GeoAtlas' in md and 'ATLAS' in md['GeoAtlas']
1906 or 'DAOD_TRUTH' in md[key]['dataType']
1907 ):
1908 md['eventTypes'].append('IS_ATLAS')
1909 # this is probably safe to assume for all files used in AnalysisBase
1910 md['eventTypes'].append('IS_PHYSICS')
1911 else:
1912 md['eventTypes'].append('IS_TESTBEAM')
1913
1914 if mode == 'peeker':
1915 if 'productionRelease' in md[key]:
1916 md['AtlasRelease'] = md[key]['productionRelease']
1917
1918 if 'generatorsInfo' in md[key]:
1919 md['generators'] = md[key]['generatorsInfo']
1920
1921 if mode == 'lite':
1922 meta_dict[filename].pop(key)
1923 break
1924
1925 if '/TagInfo' in file_content:
1926 md.update(md['/TagInfo'])
1927 md.pop('/TagInfo')
1928
1929 if '/Generation/Parameters' in file_content:
1930 md.update(md['/Generation/Parameters'])
1931 md.pop('/Generation/Parameters')
1932
1933 if '/Simulation/Parameters' in file_content:
1934 md.update(md['/Simulation/Parameters'])
1935 md.pop('/Simulation/Parameters')
1936
1937 if '/Digitization/Parameters' in file_content:
1938 md.update(md['/Digitization/Parameters'])
1939 md.pop('/Digitization/Parameters')
1940
1941 if 'CutBookkeepers' in file_content:
1942 md.update(md['CutBookkeepers'])
1943 md.pop('CutBookkeepers')
1944
1945 return meta_dict
1946
1947

◆ read_metadata()

read_metadata ( filenames,
file_type = None,
mode = 'lite',
promote = None,
meta_key_filter = None,
unique_tag_info_values = True,
ignoreNonExistingLocalFiles = False,
normalize_type_names = False )
This tool is independent of Athena framework and returns the metadata from a given file.
:param filenames: the input file from which metadata needs to be extracted.
:param file_type: the type of file. POOL or BS (bytestream: RAW, DRAW) files.
:param mode: if true, will return all metadata associated with the filename. By default, is false and this will
return a "tiny" version which have only the following keys: 'file_guid', 'file_size', 'file_type', 'nentries'.
:param normalize_type_names: report the RNTuple item types using the class names of the equivalent TTree branches,
and the TTree item names using the names of the equivalent RNTuple fields, with the items sorted, e.g. to compare
the content of RNTuple and TTree files.
:return: a dictionary of metadata for the given input file.

Definition at line 102 of file MetaReader.py.

103 unique_tag_info_values = True, ignoreNonExistingLocalFiles=False, normalize_type_names = False):
104 """
105 This tool is independent of Athena framework and returns the metadata from a given file.
106 :param filenames: the input file from which metadata needs to be extracted.
107 :param file_type: the type of file. POOL or BS (bytestream: RAW, DRAW) files.
108 :param mode: if true, will return all metadata associated with the filename. By default, is false and this will
109 return a "tiny" version which have only the following keys: 'file_guid', 'file_size', 'file_type', 'nentries'.
110 :param normalize_type_names: report the RNTuple item types using the class names of the equivalent TTree branches,
111 and the TTree item names using the names of the equivalent RNTuple fields, with the items sorted, e.g. to compare
112 the content of RNTuple and TTree files.
113 :return: a dictionary of metadata for the given input file.
114 """
115
116 # make the mode and run available in the _convert methods
117 global _gbl_mode, _gbl_run
118 _gbl_mode = mode
119 _gbl_run = None
120
121 from RootUtils import PyROOTFixes # noqa F401
122
123 # Check if the input is a file or a list of files.
124 if isinstance(filenames, str):
125 filenames = [filenames]
126
127 # Check if file_type is an allowed value
128 if file_type is not None:
129 if file_type not in ('POOL', 'BS'):
130 raise NameError('Allowed values for \'file_type\' parameter are: "POOL" or "BS": you provided "' + file_type + '"')
131 else:
132 msg.info('Forced file_type: {0}'.format(file_type))
133
134 # Check the value of mode parameter
135 if mode not in ('tiny', 'lite', 'full', 'peeker', 'iov'):
136 raise NameError('Allowed values for "mode" parameter are: "tiny", "lite", "peeker", "iov" or "full"')
137
138 if meta_key_filter is None:
139 meta_key_filter = []
140
141 # Disable 'full' and 'iov' in non-Gaudi environments
142 if not isGaudiEnv():
143 if mode in ('full', 'iov'):
144 raise NameError('The following modes are not available in AnalysisBase: "iov" and "full"')
145
146 msg.info('Current mode used: {0}'.format(mode))
147 msg.info('Current filenames: {0}'.format(filenames))
148
149 if mode != 'full' and mode !='iov' and len(meta_key_filter) > 0:
150 raise NameError('It is possible to use the meta_key_filter option only for full mode')
151 if meta_key_filter:
152 msg.info('Filter used: {0}'.format(meta_key_filter))
153
154 # create the storage object for metadata.
155 meta_dict = {}
156
157 # ----- retrieve metadata from all filename or filenames --------------------------------------------------------#
158 for filename in filenames:
159 meta_dict[filename] = {}
160 current_file_type = None
161 # reset the global Run for each file to not propagate and old value
162 _gbl_run = None
163 # Determine the file_type of the input and store this information into meta_dict
164 if not file_type:
165 if os.path.isfile(filename):
166
167 if ignoreNonExistingLocalFiles and not regex_URI_scheme.match(filename) and gSystem.AccessPathName(filename): # Attention, bizarre convention of return value!!
168 msg.warning('Ignoring not accessible file: {}'.format(filename))
169 continue
170
171 with open(filename, 'rb') as binary_file:
172 magic_file = binary_file.read(4)
173
174 if magic_file == 'root' or magic_file == b'root':
175 current_file_type = 'POOL'
176 meta_dict[filename]['file_type'] = 'POOL'
177
178 elif Project.determine() in (
179 Project.AnalysisBase, Project.AthAnalysis):
180 raise RuntimeError(
181 f"{filename} is not a ROOT file, assumed bytestream"
182 ", this is not supported in Analysis releases")
183 else:
184 current_file_type = 'BS'
185 meta_dict[filename]['file_type'] = 'BS'
186
187 # add information about the file_size of the input filename
188 meta_dict[filename]['file_size'] = os.path.getsize(filename)
189
190 # determine the file type for the remote input files
191 else:
192 if regex_BS_files.match(filename):
193 current_file_type = 'BS'
194 meta_dict[filename]['file_type'] = 'BS'
195 else:
196 current_file_type = 'POOL'
197 meta_dict[filename]['file_type'] = 'POOL'
198
199 # add information about the file_size of the input filename
200 meta_dict[filename]['file_size'] = None # None -> we can't read the file size for a remote file
201
202 else:
203 current_file_type = file_type
204
205 # ----- retrieves metadata from POOL files ------------------------------------------------------------------#
206 if current_file_type == 'POOL':
207
208 if ignoreNonExistingLocalFiles and not regex_URI_scheme.match(filename) and gSystem.AccessPathName(filename): # Attention, bizarre convention of return value!!
209 msg.warning('Ignoring not accessible file: {}'.format(filename))
210 continue
211
212 import ROOT
213 # open the file using ROOT.TFile
214 current_file = ROOT.TFile.Open( _get_pfn(filename) )
215
216 # get auto flush setting from the main EventData TTree
217 from PyUtils.PoolFile import PoolOpts
218 collectionTree = current_file.Get(PoolOpts.TTreeNames.EventData)
219 if isinstance(collectionTree, ROOT.TTree):
220 meta_dict[filename]['auto_flush'] = collectionTree.GetAutoFlush()
221
222 # read and add the 'GUID' value
223 meta_dict[filename]['file_guid'] = _read_guid(filename)
224
225 # read and add compression level and algorithm
226 meta_dict[filename]['file_comp_alg'] = current_file.GetCompressionAlgorithm()
227 meta_dict[filename]['file_comp_level'] = current_file.GetCompressionLevel()
228
229 if (
230 isRNTuple(md:=current_file.Get(PoolOpts.RNTupleNames.MetaData))
231 and mode != "tiny"
232 ):
233 meta_dict[filename]["metadata_items"] = {}
234
235 # opening without a model only reads the header and footer,
236 # the descriptor is used to decide which fields need to be read
237 descriptor_reader = ROOT.RNTupleReader.Open(md)
238 descriptor = descriptor_reader.GetDescriptor()
239 auxes = {}
240 classes_with_aux = {
241 "xAOD::FileMetaData_v1",
242 "xAOD::FileMetaDataAuxInfo_v1",
243 "xAOD::TriggerMenuAuxContainer_v1",
244 "DataVector<xAOD::TriggerMenu_v1>",
245 "xAOD::TriggerMenuJsonAuxContainer_v1",
246 "DataVector<xAOD::TriggerMenuJson_v1>",
247 "xAOD::TruthMetaDataAuxContainer_v1",
248 "DataVector<xAOD::TruthMetaData_v1>",
249 "xAOD::CutBookkeeperContainer_v1",
250 "xAOD::CutBookkeeperAuxContainer_v1",
251 "xAOD::LumiBlockRangeAuxContainer_v1",
252 "DataVector<xAOD::LumiBlockRange_v1>",
253 }
254
255 # field names to read, keyed by the dynamic attribute name
256 dynamic_fmd_fields = {}
257 # field names and types to read, keyed by the normalized name
258 selected_fields = {}
259
260 meta_filter = get_meta_filter(mode, meta_key_filter)
261
262 for field in descriptor.GetTopLevelFields():
263 normalizedName = field.GetFieldName()
264 if "index_ref" in normalizedName:
265 continue
266 if regexIOVMetaDataContainer.match(field.GetTypeName()):
267 # if field name is e.g. IOVMetaDataContainer_p1__Digitization_Parameters,
268 # strip the prefix and change underscore to slash to slash
269 normalizedName = (
270 field.GetFieldName()
271 .replace("IOVMetaDataContainer_p1_", "")
272 .replace("_", "/")
273 )
274 meta_dict[filename]["metadata_items"][normalizedName] = (
275 "IOVMetaDataContainer"
276 )
277 elif regexByteStreamMetadataContainer.match(field.GetTypeName()):
278 meta_dict[filename]["metadata_items"][field.GetFieldName()] = (
279 "ByteStreamMetadataContainer"
280 )
281 elif regexEventStreamInfo.match(field.GetTypeName()):
282 meta_dict[filename]["metadata_items"][field.GetFieldName()] = (
283 "EventStreamInfo"
284 )
285 elif regexXAODFileMetaData.match(field.GetTypeName()):
286 meta_dict[filename]["metadata_items"][
287 field.GetFieldName().replace("xAOD__", "xAOD::")
288 ] = field.GetTypeName()
289 elif regexXAODFileMetaDataAuxDyn.match(
290 normalizedName := field.GetFieldName()
291 .replace("xAOD__", "xAOD::")
292 .replace("AuxDyn:", "AuxDyn.")
293 ):
294 dynamic_fmd_fields[normalizedName.split(".")[1]] = (
295 field.GetFieldName()
296 )
297 meta_dict[filename]["metadata_items"][normalizedName] = (
298 field.GetTypeName()
299 )
300 continue
301 elif regexXAODFileMetaDataAux.match(field.GetTypeName()):
302 meta_dict[filename]["metadata_items"][
303 field.GetFieldName()
304 .replace("xAOD__", "xAOD::")
305 .replace("Aux:", "Aux.")
306 ] = field.GetTypeName()
307 elif regexXAODTruthMetaData.match(field.GetTypeName()):
308 meta_dict[filename]["metadata_items"][
309 field.GetFieldName()
310 .replace("xAOD__", "xAOD::")
311 .replace("DataVector_", "DataVector<")
312 .replace("__Truth", ">_Truth")
313 ] = "TruthMetaData"
314 elif regexXAODTruthMetaDataAux.match(field.GetTypeName()):
315 meta_dict[filename]["metadata_items"][
316 field.GetFieldName()
317 .replace("xAOD__", "xAOD::")
318 .replace("Aux:", "Aux.")
319 ] = field.GetTypeName()
320 elif regexXAODEventFormat.match(field.GetTypeName()):
321 meta_dict[filename]["metadata_items"][
322 field.GetFieldName().replace("xAOD__", "xAOD::")
323 ] = field.GetTypeName()
324 elif regexXAODTriggerMenuJson.match(field.GetTypeName()):
325 meta_dict[filename]["metadata_items"][
326 field.GetFieldName()
327 .replace("xAOD__", "xAOD::")
328 .replace("DataVector_", "DataVector<")
329 .replace("__Trigger", ">_Trigger")
330 ] = field.GetTypeName()
331 elif regexXAODTriggerMenuJsonAux.match(field.GetTypeName()):
332 meta_dict[filename]["metadata_items"][
333 field.GetFieldName()
334 .replace("xAOD__", "xAOD::")
335 .replace("Aux:", "Aux.")
336 ] = field.GetTypeName()
337 elif regexXAODCutBookkeeperContainer.match(field.GetTypeName()):
338 meta_dict[filename]["metadata_items"][
339 field.GetFieldName()
340 .replace("xAOD__", "xAOD::")
341 .replace("DataVector_", "DataVector<")
342 .replace("__CutBookkeeper", ">_CutBookkeeper")
343 ] = field.GetTypeName()
344 elif regexXAODCutBookkeeperContainerAux.match(field.GetTypeName()):
345 meta_dict[filename]["metadata_items"][
346 field.GetFieldName()
347 .replace("xAOD__", "xAOD::")
348 .replace("Aux:", "Aux.")
349 ] = field.GetTypeName()
350 else:
351 meta_dict[filename]["metadata_items"][
352 field.GetFieldName().replace("Aux:", "Aux.")
353 ] = field.GetTypeName()
354
355 if field.GetTypeName() in classes_with_aux:
356 # handle aux classes later
357 auxes[field.GetFieldName()] = field.GetTypeName()
358 continue
359
360 if not should_keep_meta(
361 normalizedName, field.GetTypeName(), meta_filter
362 ):
363 continue
364
365 selected_fields[normalizedName] = (
366 field.GetFieldName(),
367 field.GetTypeName(),
368 )
369
370 meta_dict[filename]["metadata_items"] = denormalize_metadata_types(
371 meta_dict[filename]["metadata_items"]
372 )
373
374 def _get_aux_base(aux_key: str) -> str:
375 # Remove known prefixes
376 key = aux_key
377 key = key.replace("xAOD__TriggerMenuJsonAuxContainer_v1_", "")
378 key = key.replace("xAOD__TriggerMenuAuxContainer_v1_", "")
379 key = key.replace("xAOD__FileMetaDataAuxInfo_v1_", "")
380 key = key.replace("xAOD__TruthMetaDataAuxContainer_v1_", "")
381 # Remove known suffixes
382 if key.endswith("Aux:"):
383 key = key[:-4]
384 elif key.endswith("Aux"):
385 key = key[:-3]
386 # Remove any trailing ':' or '_'
387 key = key.strip("_:")
388 return key
389
390 def _get_main_base(main_key: str) -> str:
391 main_base = main_key
392 # For DataVectors
393 if main_key.startswith("DataVector_xAOD__TriggerMenuJson_v1__"):
394 main_base = main_key.replace(
395 "DataVector_xAOD__TriggerMenuJson_v1__", ""
396 )
397 elif main_key.startswith("DataVector_xAOD__TriggerMenu_v1__"):
398 main_base = main_key.replace(
399 "DataVector_xAOD__TriggerMenu_v1__", ""
400 )
401 # For FileMetaData
402 elif main_key.startswith("xAOD__FileMetaData_v1_"):
403 main_base = main_key.replace("xAOD__FileMetaData_v1_", "")
404 # For TruthMetaData
405 elif main_key.startswith("DataVector_xAOD__TruthMetaData_v1__"):
406 main_base = main_key.replace(
407 "DataVector_xAOD__TruthMetaData_v1__", ""
408 )
409 return main_base
410
411 def _find_associated_pairs(auxes: dict) -> list[tuple[str, str]]:
412 # Build lookup tables
413 aux_map = {}
414 for k in auxes:
415 if "Aux" in k:
416 aux_map[_get_aux_base(k)] = k
417
418 main_map = {}
419 for k in auxes:
420 base = _get_main_base(k)
421 if base:
422 main_map[base] = k
423
424 # Find pairs
425 pairs = []
426 for base, aux_key in aux_map.items():
427 if base in main_map:
428 pairs.append((aux_key, main_map[base]))
429 return pairs
430
431 def _keep_pair(
432 pair: tuple[str, str], auxes: dict, meta_filter: dict
433 ) -> bool:
434 key = next(
435 (
436 k
437 for k, v in trigger_menu_json_map.items()
438 if v
439 == pair[1]
440 .replace("xAOD__", "xAOD::")
441 .replace("DataVector_", "DataVector<")
442 .replace("__Trigger", ">_Trigger")
443 ),
444 auxes[pair[0]],
445 )
446
447 try:
448 key = (
449 key.replace("xAOD__", "xAOD::")
450 if key.count("_") <= 1
451 else key.replace("xAOD__", "xAOD::").rsplit("_", 2)[0]
452 )
453 except IndexError:
454 pass
455
456 return should_keep_meta(
457 pair[0]
458 .replace("xAOD__", "xAOD::")
459 .replace("DataVector_", "DataVector<")
460 .replace("__Trigger", ">_Trigger")
461 .replace("Aux:", "Aux."),
462 key,
463 meta_filter,
464 )
465
466 selected_pairs = [
467 pair
468 for pair in _find_associated_pairs(auxes)
469 if _keep_pair(pair, auxes, meta_filter)
470 ]
471 # Some transition AODs contain both the Run2 and Run3 trigger metadata formats.
472 # We only wish to read the Run3 format if such a file is encountered.
473 if any(
474 regexXAODTriggerMenuJsonAux.match(auxes[pair[0]])
475 for pair in selected_pairs
476 ):
477 selected_pairs = [
478 pair
479 for pair in selected_pairs
480 if not regexXAODTriggerMenuAux.match(auxes[pair[0]])
481 ]
482 # dynamic attributes are only used together with the FileMetaData
483 read_dynamic_fmd = any(
484 "FileMetaData" in pair[0] for pair in selected_pairs
485 )
486
487 fields_to_read = {name for name, _ in selected_fields.values()}
488 fields_to_read.update(name for pair in selected_pairs for name in pair)
489 if read_dynamic_fmd:
490 fields_to_read.update(dynamic_fmd_fields.values())
491
492 # only the fields present in the model are read from the file
493 model = ROOT.RNTupleModel.Create()
494 for field in descriptor.GetTopLevelFields():
495 if field.GetFieldName() in fields_to_read:
496 model.AddField(ROOT.std.move(field.CreateField(descriptor)))
497
498 reader = ROOT.RNTupleReader.Open(ROOT.std.move(model), md)
499 entry = reader.CreateEntry()
500 reader.LoadEntry(0, entry)
501
502 # read the EventStreamInfo first, so only the IOVs of its run are read later
503 for normalizedName, (field_name, type_name) in sorted(
504 selected_fields.items(),
505 key=lambda item: regexEventStreamInfo.match(item[1][1]) is None,
506 ):
507 try:
508 value = _convert_value(
509 _get_entry_value(entry, field_name, type_name)
510 )
511 except KeyError:
512 msg.warning(f"missing type {type_name}")
513 continue
514 meta_dict[filename][normalizedName] = value
515 if (
516 regexEventStreamInfo.match(type_name)
517 and value
518 and len(value.get("runNumbers", [])) == 1
519 ):
520 _gbl_run = value["runNumbers"][0]
521 msg.debug("Found RunNumber in EventStreamInfo: %d", _gbl_run)
522
523 dynamic_fmd_items = {}
524 if read_dynamic_fmd:
525 for name, field_name in dynamic_fmd_fields.items():
526 value = _convert_value(entry[field_name])
527 if name.startswith("is"):
528 # this is probably a boolean
529 value = value != "\x00"
530 dynamic_fmd_items[name] = value
531
532 for pair in selected_pairs:
533 return_obj = _convert_value(
534 _get_entry_value(entry, pair[1], auxes[pair[1]]),
535 _get_entry_value(entry, pair[0], auxes[pair[0]]),
536 )
537
538 # both the Run3 TriggerMenuJson and the legacy Run2 TriggerMenu
539 if "TriggerMenu" in pair[0]:
540 if "RAWTriggerMenuJson" in return_obj:
541 key = (
542 pair[1]
543 if pair[0].startswith("Trigger")
544 else trigger_menu_json_map[pair[0]]
545 )
546 meta_dict[filename][key] = return_obj["RAWTriggerMenuJson"]
547 del return_obj["RAWTriggerMenuJson"]
548 if "TriggerConfigInfo" not in meta_dict[filename]:
549 meta_dict[filename]["TriggerConfigInfo"] = {}
550 if "dbkey" in return_obj:
551 meta_dict[filename]["TriggerConfigInfo"][
552 pair[0].split("_")[-1].replace("Aux:", "")
553 ] = {"key": return_obj["dbkey"], "name": return_obj["name"]}
554 del return_obj["dbkey"]
555 del return_obj["name"]
556 if "TriggerMenu" not in meta_dict[filename]:
557 meta_dict[filename]["TriggerMenu"] = {}
558 meta_dict[filename]["TriggerMenu"].update(return_obj)
559 elif "FileMetaData" in pair[0]:
560 if "FileMetaData" not in meta_dict[filename]:
561 meta_dict[filename]["FileMetaData"] = dynamic_fmd_items
562 meta_dict[filename]["FileMetaData"].update(return_obj)
563 elif "TruthMetaData" in pair[0]:
564 if pair == ("TruthMetaDataAux:", "TruthMetaData"):
565 if "TruthMetaData" not in meta_dict[filename]:
566 meta_dict[filename]["TruthMetaData"] = {}
567 meta_dict[filename]["TruthMetaData"].update(return_obj)
568 else:
569 # for backward compatibility
570 meta_dict[filename][
571 pair[1]
572 .replace("xAOD__", "xAOD::")
573 .replace("DataVector_", "DataVector<")
574 .replace("__Truth", ">_Truth")
575 ] = {}
576 meta_dict[filename][
577 pair[0]
578 .replace("xAOD__", "xAOD::")
579 .replace("Aux:", "Aux.")
580 ] = {}
581 elif pair == ("CutBookkeepersAux:", "CutBookkeepers"):
582 meta_dict[filename]["CutBookkeepers"] = return_obj
583
584 msg.debug(f"Read metadata from RNTuple: {meta_dict[filename]}")
585
586 else:
587 # ----- read extra metadata required for 'lite' and 'full' modes ----------------------------------------#
588 if mode != 'tiny':
589 # selecting from all tree the only one which contains metadata, respectively "MetaData"
590 metadata_tree = current_file.Get('MetaData')
591 # read all list of branches stored in "MetaData" tree
592 metadata_branches = metadata_tree.GetListOfBranches()
593 nr_of_branches = metadata_branches.GetEntriesFast()
594
595 # object to store the names of metadata containers and their corresponding class name.
596 meta_dict[filename]['metadata_items'] = {}
597
598 meta_filter = get_meta_filter(mode, meta_key_filter)
599
600 # store all persistent classes for metadata container existing in a POOL/ROOT file.
601 persistent_instances = {}
602 dynamic_fmd_items = {}
603
604 # Protect non-Gaudi environments from meta-data classes it doesn't know about
605 if not isGaudiEnv():
606 metadata_tree.SetBranchStatus("*", False)
607
608 for i in range(0, nr_of_branches):
609 branch = metadata_branches.At(i)
610 name = branch.GetName()
611 if name == 'index_ref':
612 # skip the index branch
613 continue
614
615 class_name = branch.GetClassName()
616
617 if regexIOVMetaDataContainer.match(class_name):
618 name = name.replace('IOVMetaDataContainer_p1_', '').replace('_', '/')
619
620 if regexIOVMetaDataContainer.match(class_name):
621 meta_dict[filename]['metadata_items'][name] = 'IOVMetaDataContainer'
622 elif regexByteStreamMetadataContainer.match(class_name):
623 meta_dict[filename]['metadata_items'][name] = 'ByteStreamMetadataContainer'
624 elif regexEventStreamInfo.match(class_name):
625 meta_dict[filename]['metadata_items'][name] = 'EventStreamInfo'
626 elif regexXAODFileMetaData.match(class_name):
627 meta_dict[filename]['metadata_items'][name] = 'FileMetaData'
628 elif regexXAODTruthMetaData.match(class_name):
629 meta_dict[filename]['metadata_items'][name] = 'TruthMetaData'
630 else:
631 type_name = class_name
632 if not type_name:
633 try:
634 type_name = branch.GetListOfLeaves()[0].GetTypeName()
635 except IndexError:
636 pass
637 meta_dict[filename]['metadata_items'][name] = type_name
638
639 if len(meta_filter) > 0:
640 keep = False
641 for filter_key, filter_class in meta_filter.items():
642 if (filter_key.replace('/', '_') in name.replace('/', '_') or filter_key == '*') and fnmatchcase(class_name, filter_class):
643 if 'CutBookkeepers' in filter_key:
644 keep = filter_key == name
645 if keep:
646 break
647 else:
648 keep = True
649 break
650
651 if not keep:
652 continue
653 else:
654 # CutBookkeepers should always be filtered:
655 if 'CutBookkeepers' in name and name not in ['CutBookkeepers', 'CutBookkeepersAux.']:
656 continue
657
658 if not isGaudiEnv():
659 metadata_tree.SetBranchStatus(f"{name}*", True)
660
661 # assign the corresponding persistent class based of the name of the metadata container
662 if regexEventStreamInfo.match(class_name):
663 if class_name.endswith('_p1'):
664 persistent_instances[name] = ROOT.EventStreamInfo_p1()
665 elif class_name.endswith('_p2'):
666 persistent_instances[name] = ROOT.EventStreamInfo_p2()
667 else:
668 persistent_instances[name] = ROOT.EventStreamInfo_p3()
669 elif regexIOVMetaDataContainer.match(class_name):
670 persistent_instances[name] = ROOT.IOVMetaDataContainer_p1()
671 elif regexByteStreamMetadataContainer.match(class_name):
672 persistent_instances[name] = ROOT.ByteStreamMetadataContainer_p1()
673 elif regexXAODEventFormat.match(class_name):
674 persistent_instances[name] = ROOT.xAOD.EventFormat_v1()
675 elif regexXAODTriggerMenu.match(class_name) and _check_project() not in ['AthGeneration']:
676 persistent_instances[name] = ROOT.xAOD.TriggerMenuContainer_v1()
677 elif regexXAODTriggerMenuAux.match(class_name) and _check_project() not in ['AthGeneration']:
678 persistent_instances[name] = ROOT.xAOD.TriggerMenuAuxContainer_v1()
679 elif regexXAODTriggerMenuJson.match(class_name) and _check_project() not in ['AthGeneration']:
680 persistent_instances[name] = ROOT.xAOD.TriggerMenuJsonContainer_v1()
681 elif regexXAODTriggerMenuJsonAux.match(class_name) and _check_project() not in ['AthGeneration']:
682 persistent_instances[name] = ROOT.xAOD.TriggerMenuJsonAuxContainer_v1()
683 elif regexXAODCutBookkeeperContainer.match(class_name):
684 persistent_instances[name] = ROOT.xAOD.CutBookkeeperContainer_v1()
685 elif regexXAODCutBookkeeperContainerAux.match(class_name):
686 persistent_instances[name] = ROOT.xAOD.CutBookkeeperAuxContainer_v1()
687 elif regexXAODFileMetaData.match(class_name):
688 persistent_instances[name] = ROOT.xAOD.FileMetaData_v1()
689 elif regexXAODFileMetaDataAux.match(class_name):
690 persistent_instances[name] = ROOT.xAOD.FileMetaDataAuxInfo_v1()
691 elif regexXAODTruthMetaData.match(class_name):
692 persistent_instances[name] = ROOT.xAOD.TruthMetaDataContainer_v1()
693 elif regexXAODTruthMetaDataAux.match(class_name):
694 persistent_instances[name] = ROOT.xAOD.TruthMetaDataAuxContainer_v1()
695
696 if name in persistent_instances:
697 branch.SetAddress(ROOT.AddressOf(persistent_instances[name]))
698
699 # This creates a dict to store the dynamic attributes of the xAOD::FileMetaData
700 dynamicFMD = regexXAODFileMetaDataAuxDyn.match(name)
701 if dynamicFMD:
702 dynamicName = dynamicFMD.group().split('.')[-1]
703 dynamicType = regex_cppname.match(class_name)
704 if dynamicType:
705 # this should be a string
706 dynamic_fmd_items[dynamicName] = ROOT.std.string()
707 branch.SetAddress(ROOT.AddressOf(dynamic_fmd_items[dynamicName]))
708 else:
709 dynamic_fmd_items[dynamicName] = None
710
711
712 metadata_tree.GetEntry(0)
713
714 # This loads the dynamic attributes of the xAOD::FileMetaData from the TTree
715 for key in dynamic_fmd_items:
716 if dynamic_fmd_items[key] is None:
717 try:
718 if key.startswith("is"):
719 # this is probably a boolean
720 dynamic_fmd_items[key] = getattr(metadata_tree, key) != '\x00'
721 else:
722 # this should be a float
723 dynamic_fmd_items[key] = getattr(metadata_tree, key)
724 except AttributeError:
725 # should not happen, but just ignore missing attributes
726 pass
727 else:
728 # convert ROOT.std.string objects to python equivalent
729 dynamic_fmd_items[key] = str(dynamic_fmd_items[key])
730
731 # clean the meta-dict if the meta_key_filter flag is used, to return only the key of interest
732 if meta_key_filter:
733 meta_dict[filename] = {}
734
735 # Find the RunNumber from EventStreamInfo, so only the relevant IOVs are read later
736 for key, obj in persistent_instances.items():
737 if key.startswith('EventStreamInfo'):
738 data = _convert_value(obj, None)
739 if data and 'runNumbers' in data and len(data['runNumbers']) == 1:
740 _gbl_run = data['runNumbers'][0]
741 msg.debug("Found RunNumber in EventStreamInfo: %d", _gbl_run)
742
743 # read the metadata
744 for name, content in persistent_instances.items():
745 key = name
746 if hasattr(content, 'm_folderName'):
747 key = content.m_folderName
748
749 # Some transition AODs contain both the Run2 and Run3 metadata formats. We only wish to read the Run3 format if such a file is encountered.
750 has_r3_trig_meta = ('TriggerMenuJson_HLT' in persistent_instances or 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT' in persistent_instances)
751 aux = None
752 if key.startswith('TriggerMenuJson_') and not key.endswith('Aux.'): # interface container for the menu (AOD)
753 aux = persistent_instances[key+'Aux.']
754 elif key.startswith('DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_') and not key.endswith('Aux.'): # interface container for the menu (ESD)
755 menuPart = key.split('_')[-1]
756 aux = persistent_instances['xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_'+menuPart+'Aux.']
757 elif key == 'TriggerMenu' and 'TriggerMenuAux.' in persistent_instances and not has_r3_trig_meta: # AOD case (legacy support, HLT and L1 menus)
758 aux = persistent_instances['TriggerMenuAux.']
759 elif key == 'DataVector<xAOD::TriggerMenu_v1>_TriggerMenu' and 'xAOD::TriggerMenuAuxContainer_v1_TriggerMenuAux.' in persistent_instances and not has_r3_trig_meta: # ESD case (legacy support, HLT and L1 menus)
760 aux = persistent_instances['xAOD::TriggerMenuAuxContainer_v1_TriggerMenuAux.']
761 elif (key == 'CutBookkeepers'
762 and 'CutBookkeepersAux.' in persistent_instances):
763 aux = persistent_instances['CutBookkeepersAux.']
764 elif key == 'CutBookkeepersAux.':
765 continue # Extracted using the interface object
766 elif (key == 'FileMetaData'
767 and 'FileMetaDataAux.' in persistent_instances):
768 aux = persistent_instances['FileMetaDataAux.']
769 elif (key == 'xAOD::FileMetaData_v1_FileMetaData'
770 and 'xAOD::FileMetaDataAuxInfo_v1_FileMetaDataAux.' in persistent_instances):
771 aux = persistent_instances['xAOD::FileMetaDataAuxInfo_v1_FileMetaDataAux.']
772 elif (key == 'TruthMetaData'
773 and 'TruthMetaDataAux.' in persistent_instances):
774 aux = persistent_instances['TruthMetaDataAux.']
775 elif key == 'TruthMetaDataAux.':
776 continue # Extracted using the interface object
777 elif 'Menu' in key and key.endswith('Aux.'):
778 continue # Extracted using the interface object
779
780 return_obj = _convert_value(content, aux)
781
782 if 'TriggerMenuJson' in key or ('TriggerMenu' in key and not has_r3_trig_meta):
783 if 'RAWTriggerMenuJson' in return_obj:
784 meta_dict[filename][key] = return_obj['RAWTriggerMenuJson']
785 del return_obj['RAWTriggerMenuJson']
786 if 'TriggerConfigInfo' not in meta_dict[filename]:
787 meta_dict[filename]['TriggerConfigInfo'] = {}
788 if 'dbkey' in return_obj:
789 meta_dict[filename]['TriggerConfigInfo'][key.split('_')[-1]] = {
790 'key' : return_obj['dbkey'],
791 'name': return_obj['name']
792 }
793 del return_obj['dbkey']
794 del return_obj['name']
795 if 'TriggerMenu' not in meta_dict[filename]:
796 meta_dict[filename]['TriggerMenu'] = {}
797 meta_dict[filename]['TriggerMenu'].update(return_obj)
798 elif "FileMetaData" in key:
799 if "FileMetaData" not in meta_dict[filename]:
800 meta_dict[filename]["FileMetaData"] = dynamic_fmd_items
801 meta_dict[filename]["FileMetaData"].update(return_obj)
802 else:
803 meta_dict[filename][key] = return_obj
804
805 try:
806 # get the number of events from EventStreamInfo
807 esi_dict = next(key for key, value in meta_dict[filename].items()
808 if isinstance(value, dict) and "numberOfEvents" in value and
809 meta_dict[filename]["metadata_items"][key] == "EventStreamInfo")
810 msg.debug(f"{esi_dict=}")
811 meta_dict[filename]["nentries"] = meta_dict[filename][esi_dict]["numberOfEvents"]
812 except StopIteration as err:
813 msg.debug(f"Caught {err=}, {type(err)=}, falling back on opening the DataHeader"
814 " Container to read the number of entries")
815 meta_dict[filename]['nentries'] = dataheader_nentries(current_file)
816 msg.debug(f"{meta_dict[filename]['nentries']=}")
817
818 if unique_tag_info_values and mode=='iov':
819 unique_tag_info_values = False
820 msg.info('disabling "unique_tag_info_values" option for "iov" mode')
821
822 # This is a required workaround which will temporarily be fixing ATEAM-560 originated from ATEAM-531
823 # ATEAM-560: https://its.cern.ch/jira/browse/ATEAM-560
824 # ATEAM-531: https://its.cern.ch/jira/browse/ATEAM-531
825 # This changes will remove all duplicates values presented in some files due
826 # to the improper merging of two IOVMetaDataContainers.
827 if unique_tag_info_values:
828 msg.info('MetaReader is called with the parameter "unique_tag_info_values" set to True. '
829 'This is a workaround to remove all duplicate values from "/TagInfo" key')
830 if '/TagInfo' in meta_dict[filename]:
831 for key, value in meta_dict[filename]['/TagInfo'].items():
832 if isinstance(value, list) and value:
833 if len(unique_values := set(value)) > 1:
834 msg.warning(
835 f"Found multiple values for {key}: {value}. "
836 "Looking for possible duplicates."
837 )
838 maybe_ok = False
839 if key == "AMITag":
840 # curate duplicates like: ['s3681_q453', 's3681_q453_'] or ["s3681_q453", "q453_s3681"]
841 unique_amitags = set()
842 for amitags in unique_values:
843 unique_amitags.add(
844 "_".join([tag for tag in amitags.split("_") if tag])
845 )
846 # Remove tags that are parents - are contained in other tags
847 # Such that ["s3681","s3681_d1485"] keeps only the latter
848 parent_tags = []
849 for atag in unique_amitags:
850 if any(atag+'_' in x for x in unique_amitags if x != atag):
851 parent_tags += [atag]
852 for atag in parent_tags:
853 # Do not remove the last tag!
854 if len(unique_amitags)>1:
855 msg.warning(f"Removing parent AMI tag {atag}")
856 unique_amitags.remove(atag)
857 if len(unique_amitags) == 1:
858 maybe_ok = True
859 # Make sure we keep the one we want to keep
860 value.insert(0,list(unique_amitags)[0])
861 elif key == "beam_energy":
862 # handle duplicates like: ['6500000', '6500000.0'] or [3, "3"]
863 unique_energies = set()
864 for energy in unique_values:
865 try:
866 energy = int(energy)
867 except ValueError:
868 try:
869 energy = float(energy)
870 except ValueError:
871 pass
872 unique_energies.add(energy)
873 if len(unique_energies) == 1:
874 maybe_ok = True
875 # randomSeed is maybe_ok due to mc16 corruption test failures (see ATLASG-3193)
876 elif key in ["AtlasRelease", "IOVDbGlobalTag", "AODFixVersion", "randomSeed"]:
877 maybe_ok = True
878 if maybe_ok:
879 msg.warning(
880 f"Multiple values for {key} may mean the same, or "
881 "the input file was produced in multi-step job. "
882 f"Ignoring all but the first entry: {key} = {value[0]}"
883 )
884 else:
885 raise ValueError(
886 f"{key} from /TagInfo contains more than 1 unique value: {value}"
887 )
888
889 meta_dict[filename]['/TagInfo'][key] = value[0]
890
891 if promote is None:
892 promote = mode == 'lite' or mode == 'peeker'
893
894 # Filter the data and create a prettier output for the 'lite' mode
895 if mode == 'lite':
896 meta_dict = make_lite(meta_dict)
897
898 if mode == 'peeker':
899 meta_dict = make_peeker(meta_dict)
900
901 if promote:
902 meta_dict = promote_keys(meta_dict, mode)
903
904 # If AnalysisBase the itemList must be grabbed another way
905 if not isGaudiEnv():
906 if isinstance(collectionTree, ROOT.TTree):
907 item_list = [
908 (str(b.GetClassName()), str(b.GetName())) for b in collectionTree.GetListOfBranches()
909 ]
910 if normalize_type_names:
911 item_list = [
912 (type_name, _branch_name_to_field_name(name)) for type_name, name in item_list
913 ]
914 elif isRNTuple(eventData := current_file.Get(PoolOpts.RNTupleNames.EventData)):
915 # keep the reader alive while iterating, as the descriptor is owned by it
916 eventDataReader = ROOT.RNTupleReader.Open(eventData)
917 # RNTuple fields use "Aux:"/"AuxDyn:" instead of "Aux."/"AuxDyn.",
918 # convert them to the branch names used for TTree above
919 item_list = [
920 (str(f.GetTypeName()), re.sub(r'Aux(Dyn)?:', r'Aux\1.', str(f.GetFieldName()), count=1))
921 for f in eventDataReader.GetDescriptor().GetTopLevelFields()
922 if not str(f.GetTypeName()).startswith('DataHeader')
923 ]
924 if normalize_type_names:
925 item_list = [
926 (_rntuple_type_to_class_name(type_name), name) for type_name, name in item_list
927 ]
928 if normalize_type_names:
929 # the order of the TTree branches and RNTuple fields is not related
930 item_list.sort()
931 meta_dict[filename]['itemList'] = item_list
932
933 # ----- retrieves metadata from bytestream (BS) files (RAW, DRAW) ------------------------------------------#
934 elif current_file_type == 'BS':
935
936 if ignoreNonExistingLocalFiles and not regex_URI_scheme.match(filename) and not os.path.isfile(filename):
937 msg.warning('Ignoring not accessible file: {}'.format(filename))
938 continue
939
940 import eformat
941
942 # store the number of entries
943 bs = eformat.istream(filename)
944 meta_dict[filename]['nentries'] = bs.total_events
945
946 # store the 'guid' value
947 data_reader = eformat.EventStorage.pickDataReader(filename)
948 assert data_reader, 'problem picking a data reader for file [%s]' % filename
949
950 # set auto flush equivalent, which for BS is always 1
951 meta_dict[filename]['auto_flush'] = 1
952
953 if hasattr(data_reader, 'GUID'):
954 meta_dict[filename]['file_guid'] = data_reader.GUID()
955
956 # compression level and algorithm, for BS always ZLIB
957 meta_dict[filename]['file_comp_alg'] = 1
958 meta_dict[filename]['file_comp_level'] = 1
959
960
961 # if the flag full is set to true then grab all metadata
962 # ------------------------------------------------------------------------------------------------------#
963 if mode != "tiny":
964 bs_metadata = {}
965
966 for md in data_reader.freeMetaDataStrings():
967 if md.startswith('Event type:'):
968 k = 'eventTypes'
969 v = []
970 if 'is sim' in md:
971 v.append('IS_SIMULATION')
972 else:
973 v.append('IS_DATA')
974
975 if 'is atlas' in md:
976 v.append('IS_ATLAS')
977 else:
978 v.append('IS_TESTBEAM')
979
980 if 'is physics' in md:
981 v.append('IS_PHYSICS')
982 else:
983 v.append('IS_CALIBRATION')
984
985 bs_metadata[k] = tuple(v)
986
987 elif md.startswith('GeoAtlas:'):
988 k = 'geometry'
989 v = md.split('GeoAtlas:')[1].strip()
990 bs_metadata[k] = v
991
992 elif md.startswith('IOVDbGlobalTag:'):
993 k = 'conditions_tag'
994 v = md.split('IOVDbGlobalTag:')[1].strip()
995 bs_metadata[k] = v
996
997 elif '=' in md:
998 k, v = md.split('=', 1) # Split on first '=' only
999 bs_metadata[k] = v
1000
1001 bs_metadata['detectorMask'] = data_reader.detectorMask()
1002 bs_metadata['runNumbers'] = data_reader.runNumber()
1003 bs_metadata['lumiBlockNumbers'] = data_reader.lumiblockNumber()
1004 bs_metadata['projectTag'] = data_reader.projectTag()
1005 bs_metadata['stream'] = data_reader.stream()
1006 #bs_metadata['beamType'] = getattr(data_reader, 'beamType')()
1007 beamTypeNbr= data_reader.beamType()
1008 #According to info from Rainer and Guiseppe the beam type is
1009 #O: no beam
1010 #1: protons
1011 #2: ions
1012 if (beamTypeNbr==0): bs_metadata['beamType'] = 'cosmics'
1013 elif (beamTypeNbr==1 or beamTypeNbr==2): bs_metadata['beamType'] = 'collisions'
1014 else: bs_metadata['beamType'] = 'unknown'
1015
1016 bs_metadata['beamEnergy'] = data_reader.beamEnergy()
1017
1018 meta_dict[filename]['eventTypes'] = bs_metadata.get('eventTypes', [])
1019 meta_dict[filename]['GeoAtlas'] = bs_metadata.get('geometry', None)
1020 meta_dict[filename]['conditions_tag'] = bs_metadata.get('conditions_tag', None)
1021 meta_dict[filename]['project_name'] = bs_metadata.get('projectTag', None)
1022
1023 # Promote up one level
1024 meta_dict[filename]['detectorMask'] = [bs_metadata.get('detectorMask', None)]
1025 meta_dict[filename]['runNumbers'] = [bs_metadata.get('runNumbers', None)]
1026 meta_dict[filename]['lumiBlockNumbers'] = [bs_metadata.get('lumiBlockNumbers', None)]
1027 meta_dict[filename]['beam_type'] = bs_metadata.get('beamType', None)
1028 meta_dict[filename]['beam_energy'] = bs_metadata.get('beamEnergy', None)
1029 meta_dict[filename]['stream'] = bs_metadata.get('stream', None)
1030
1031 if not data_reader.good():
1032 # event-less file...
1033 meta_dict[filename]['runNumbers'].append(bs_metadata.get('run_number', 0))
1034 meta_dict[filename]['lumiBlockNumbers'].append(bs_metadata.get('LumiBlock', 0))
1035
1036 msg.debug(f"{meta_dict[filename]=}")
1037 msg.debug(f"{len(bs)=}")
1038 if len(bs):
1039 evt = bs[0]
1040 try:
1041 evt.check()
1042 meta_dict[filename]['processingTags'] = [tag.name for tag in evt.stream_tag()]
1043 meta_dict[filename]['evt_number'] = [evt.global_id()]
1044 meta_dict[filename]['run_type'] = [eformat.helper.run_type2string(evt.run_type())]
1045 # ATLASRECTS-7126: If there is no valid lumiblock information
1046 # in the ByteStream header, get the info from the first event.
1047 if meta_dict[filename]['lumiBlockNumbers'] == [0]:
1048 msg.debug('Taking the luminosity block info from the first event (%i)', evt.lumi_block())
1049 meta_dict[filename]['lumiBlockNumbers'] = [evt.lumi_block()]
1050 # ATLASRECTS-7126: If there is no valid run number information
1051 # in the ByteStream header, get the info from the first event.
1052 if meta_dict[filename]['runNumbers'] == [0]:
1053 msg.debug('Taking the run number info from the first event (%i)', evt.run_no())
1054 meta_dict[filename]['runNumbers'] = [evt.run_no()]
1055 except RuntimeError as err:
1056 msg.error("Issue while reading the first event of BS file %r: %r", filename, err)
1057 else:
1058 msg.debug(f"{meta_dict[filename]=}")
1059 else:
1060 msg.warning(f"Event-less BS {filename=}, will not read metadata information from the first event")
1061
1062 # fix for ATEAM-122
1063 if len(bs_metadata.get('eventTypes', '')) == 0: # see: ATMETADATA-6
1064 evt_type = ['IS_DATA', 'IS_ATLAS']
1065 if bs_metadata.get('stream', '').startswith('physics_'):
1066 evt_type.append('IS_PHYSICS')
1067 elif bs_metadata.get('stream', '').startswith('calibration_'):
1068 evt_type.append('IS_CALIBRATION')
1069 elif bs_metadata.get('projectTag', '').endswith('_calib'):
1070 evt_type.append('IS_CALIBRATION')
1071 else:
1072 evt_type.append('Unknown')
1073
1074 meta_dict[filename]['eventTypes'] = evt_type
1075
1076 if mode == 'full':
1077 meta_dict[filename]['bs_metadata'] = bs_metadata
1078
1079 # ------ Throw an error if the user provide other file types -------------------------------------------------#
1080 else:
1081 msg.error('Unknown filetype for {0} - there is no metadata interface for type {1}'.format(filename, current_file_type))
1082 return None
1083
1084 return meta_dict
1085
1086
STL class.
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312

◆ should_keep_meta()

should_keep_meta ( normalizedName,
typeName,
meta_filter )
Helper function to determine if metadata should be kept based on meta_filter.

Definition at line 2133 of file MetaReader.py.

2133def should_keep_meta(normalizedName, typeName, meta_filter):
2134 """
2135 Helper function to determine if metadata should be kept based on meta_filter.
2136 """
2137 if len(meta_filter) == 0:
2138 return True
2139
2140 for filter_key, filter_class in meta_filter.items():
2141 if (
2142 filter_key.replace("/", "_") in normalizedName.replace("/", "_")
2143 or filter_key == "*"
2144 ) and fnmatchcase(typeName, filter_class):
2145 if "CutBookkeepers" in filter_key:
2146 keep = filter_key == normalizedName
2147 if keep:
2148 return True
2149 else:
2150 return True
2151 return False

Variable Documentation

◆ _rntuple_fundamental_types

dict python.MetaReader._rntuple_fundamental_types = {'bool', 'char', 'float', 'double', *_rntuple_integer_types}
protected

Definition at line 82 of file MetaReader.py.

◆ _rntuple_integer_types

dict python.MetaReader._rntuple_integer_types
protected
Initial value:
= {
'std::int8_t': 'signed char',
'std::uint8_t': 'unsigned char',
'std::int16_t': 'short',
'std::uint16_t': 'unsigned short',
'std::int32_t': 'int',
'std::uint32_t': 'unsigned int',
'std::int64_t': 'long',
'std::uint64_t': 'unsigned long',
}

Definition at line 72 of file MetaReader.py.

◆ lite_primary_keys_to_keep

list python.MetaReader.lite_primary_keys_to_keep
Initial value:
= [
'lumiBlockNumbers', 'runNumbers', 'mc_event_number', 'mc_channel_number',
'eventTypes', 'processingTags', 'itemList']

Definition at line 39 of file MetaReader.py.

◆ lite_TagInfo_keys_to_keep

list python.MetaReader.lite_TagInfo_keys_to_keep
Initial value:
= [
'beam_energy', 'beam_type', 'GeoAtlas', 'IOVDbGlobalTag',
'AODFixVersion', 'project_name', 'mc_campaign', 'keywords']

Definition at line 42 of file MetaReader.py.

◆ msg

python.MetaReader.msg = logging.getLogger('MetaReader')

Definition at line 15 of file MetaReader.py.

◆ regex_BS_files

python.MetaReader.regex_BS_files = re.compile(r'^(\w+):.*((\.D?RAW\..*)|(\.data$))')

Definition at line 36 of file MetaReader.py.

◆ regex_cppname

python.MetaReader.regex_cppname = re.compile(r'^([\w:]+)(<.*>)?$')

Definition at line 33 of file MetaReader.py.

◆ regex_persistent_class

python.MetaReader.regex_persistent_class = re.compile(r'^([a-zA-Z]+(_[pv]\d+)?::)*[a-zA-Z]+_[pv]\d+$')

Definition at line 35 of file MetaReader.py.

◆ regex_URI_scheme

python.MetaReader.regex_URI_scheme = re.compile(r'^([A-Za-z0-9\+\.\-]+)\:')

Definition at line 37 of file MetaReader.py.

◆ regexByteStreamMetadataContainer

python.MetaReader.regexByteStreamMetadataContainer = re.compile(r'^ByteStreamMetadataContainer(_p\d+)?$')

Definition at line 20 of file MetaReader.py.

◆ regexEventStreamInfo

python.MetaReader.regexEventStreamInfo = re.compile(r'^EventStreamInfo(_p\d+)?$')

Definition at line 18 of file MetaReader.py.

◆ regexIOVMetaDataContainer

python.MetaReader.regexIOVMetaDataContainer = re.compile(r'^IOVMetaDataContainer(_p\d+)?$')

Definition at line 19 of file MetaReader.py.

◆ regexXAODCutBookkeeperContainer

python.MetaReader.regexXAODCutBookkeeperContainer = re.compile(r'^xAOD::CutBookkeeperContainer(_v\d+)?$')

Definition at line 21 of file MetaReader.py.

◆ regexXAODCutBookkeeperContainerAux

python.MetaReader.regexXAODCutBookkeeperContainerAux = re.compile(r'^xAOD::CutBookkeeperAuxContainer(_v\d+)?$')

Definition at line 22 of file MetaReader.py.

◆ regexXAODEventFormat

python.MetaReader.regexXAODEventFormat = re.compile(r'^xAOD::EventFormat(_v\d+)?$')

Definition at line 23 of file MetaReader.py.

◆ regexXAODFileMetaData

python.MetaReader.regexXAODFileMetaData = re.compile(r'^xAOD::FileMetaData(_v\d+)?$')

Definition at line 24 of file MetaReader.py.

◆ regexXAODFileMetaDataAux

python.MetaReader.regexXAODFileMetaDataAux = re.compile(r'^xAOD::FileMetaDataAuxInfo(_v\d+)?$')

Definition at line 25 of file MetaReader.py.

◆ regexXAODFileMetaDataAuxDyn

python.MetaReader.regexXAODFileMetaDataAuxDyn = re.compile(r'^(xAOD::)?FileMetaData.*AuxDyn(\.[a-zA-Z0-9]+)?$')

Definition at line 26 of file MetaReader.py.

◆ regexXAODTriggerMenu

python.MetaReader.regexXAODTriggerMenu = re.compile(r'^DataVector<xAOD::TriggerMenu(_v\d+)?>$')

Definition at line 27 of file MetaReader.py.

◆ regexXAODTriggerMenuAux

python.MetaReader.regexXAODTriggerMenuAux = re.compile(r'^xAOD::TriggerMenuAuxContainer(_v\d+)?$')

Definition at line 28 of file MetaReader.py.

◆ regexXAODTriggerMenuJson

python.MetaReader.regexXAODTriggerMenuJson = re.compile(r'^DataVector<xAOD::TriggerMenuJson(_v\d+)?>$')

Definition at line 29 of file MetaReader.py.

◆ regexXAODTriggerMenuJsonAux

python.MetaReader.regexXAODTriggerMenuJsonAux = re.compile(r'^xAOD::TriggerMenuJsonAuxContainer(_v\d+)?$')

Definition at line 30 of file MetaReader.py.

◆ regexXAODTruthMetaData

python.MetaReader.regexXAODTruthMetaData = re.compile(r'^DataVector<xAOD::TruthMetaData(_v\d+)?>$')

Definition at line 31 of file MetaReader.py.

◆ regexXAODTruthMetaDataAux

python.MetaReader.regexXAODTruthMetaDataAux = re.compile(r'^xAOD::TruthMetaDataAuxContainer(_v\d+)?$')

Definition at line 32 of file MetaReader.py.

◆ trigger_keys

list python.MetaReader.trigger_keys
Initial value:
= [
'TriggerConfigInfo',
'TriggerMenu', 'TriggerMenuJson_BG', 'TriggerMenuJson_HLT', 'TriggerMenuJson_HLTMonitoring', 'TriggerMenuJson_HLTPS', 'TriggerMenuJson_L1', 'TriggerMenuJson_L1PS',
'/TRIGGER/HLT/Groups', '/TRIGGER/HLT/HltConfigKeys', '/TRIGGER/HLT/Menu', '/TRIGGER/HLT/PrescaleKey', '/TRIGGER/HLT/Prescales',
'/TRIGGER/LVL1/ItemDef', '/TRIGGER/LVL1/Lvl1ConfigKey', '/TRIGGER/LVL1/Menu', '/TRIGGER/LVL1/Prescales', '/TRIGGER/LVL1/Thresholds',
'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenu', 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_BG', 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT',
'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTMonitoring', 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTPS',
'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1', 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1PS',
]

Definition at line 46 of file MetaReader.py.

◆ trigger_menu_json_map

dict python.MetaReader.trigger_menu_json_map
Initial value:
= {
"xAOD__TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_L1PSAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1PS",
"xAOD__TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_BGAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_BG",
"xAOD__TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_HLTAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT",
"xAOD__TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_HLTMonitoringAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTMonitoring",
"xAOD__TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_HLTPSAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTPS",
"xAOD__TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_L1Aux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1",
"TriggerMenuJson_L1PSAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1PS",
"TriggerMenuJson_BGAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_BG",
"TriggerMenuJson_HLTAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT",
"TriggerMenuJson_HLTMonitoringAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTMonitoring",
"TriggerMenuJson_HLTPSAux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLTPS",
"TriggerMenuJson_L1Aux:": "DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_L1",
}

Definition at line 56 of file MetaReader.py.