102def read_metadata(filenames, file_type = None, mode = 'lite', promote = None, meta_key_filter = None,
103 unique_tag_info_values = True, ignoreNonExistingLocalFiles=False, normalize_type_names = False):
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.
117 global _gbl_mode, _gbl_run
121 from RootUtils
import PyROOTFixes
124 if isinstance(filenames, str):
125 filenames = [filenames]
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 +
'"')
132 msg.info(
'Forced file_type: {0}'.format(file_type))
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"')
138 if meta_key_filter
is None:
143 if mode
in (
'full',
'iov'):
144 raise NameError(
'The following modes are not available in AnalysisBase: "iov" and "full"')
146 msg.info(
'Current mode used: {0}'.format(mode))
147 msg.info(
'Current filenames: {0}'.format(filenames))
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')
152 msg.info(
'Filter used: {0}'.format(meta_key_filter))
158 for filename
in filenames:
159 meta_dict[filename] = {}
160 current_file_type =
None
165 if os.path.isfile(filename):
167 if ignoreNonExistingLocalFiles
and not regex_URI_scheme.match(filename)
and gSystem.AccessPathName(filename):
168 msg.warning(
'Ignoring not accessible file: {}'.format(filename))
171 with open(filename,
'rb')
as binary_file:
172 magic_file = binary_file.read(4)
174 if magic_file ==
'root' or magic_file == b
'root':
175 current_file_type =
'POOL'
176 meta_dict[filename][
'file_type'] =
'POOL'
178 elif Project.determine()
in (
179 Project.AnalysisBase, Project.AthAnalysis):
181 f
"{filename} is not a ROOT file, assumed bytestream"
182 ", this is not supported in Analysis releases")
184 current_file_type =
'BS'
185 meta_dict[filename][
'file_type'] =
'BS'
188 meta_dict[filename][
'file_size'] = os.path.getsize(filename)
192 if regex_BS_files.match(filename):
193 current_file_type =
'BS'
194 meta_dict[filename][
'file_type'] =
'BS'
196 current_file_type =
'POOL'
197 meta_dict[filename][
'file_type'] =
'POOL'
200 meta_dict[filename][
'file_size'] =
None
203 current_file_type = file_type
206 if current_file_type ==
'POOL':
208 if ignoreNonExistingLocalFiles
and not regex_URI_scheme.match(filename)
and gSystem.AccessPathName(filename):
209 msg.warning(
'Ignoring not accessible file: {}'.format(filename))
214 current_file = ROOT.TFile.Open(
_get_pfn(filename) )
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()
223 meta_dict[filename][
'file_guid'] =
_read_guid(filename)
226 meta_dict[filename][
'file_comp_alg'] = current_file.GetCompressionAlgorithm()
227 meta_dict[filename][
'file_comp_level'] = current_file.GetCompressionLevel()
230 isRNTuple(md:=current_file.Get(PoolOpts.RNTupleNames.MetaData))
233 meta_dict[filename][
"metadata_items"] = {}
237 descriptor_reader = ROOT.RNTupleReader.Open(md)
238 descriptor = descriptor_reader.GetDescriptor()
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>",
256 dynamic_fmd_fields = {}
262 for field
in descriptor.GetTopLevelFields():
263 normalizedName = field.GetFieldName()
264 if "index_ref" in normalizedName:
266 if regexIOVMetaDataContainer.match(field.GetTypeName()):
271 .
replace(
"IOVMetaDataContainer_p1_",
"")
274 meta_dict[filename][
"metadata_items"][normalizedName] = (
275 "IOVMetaDataContainer"
277 elif regexByteStreamMetadataContainer.match(field.GetTypeName()):
278 meta_dict[filename][
"metadata_items"][field.GetFieldName()] = (
279 "ByteStreamMetadataContainer"
281 elif regexEventStreamInfo.match(field.GetTypeName()):
282 meta_dict[filename][
"metadata_items"][field.GetFieldName()] = (
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()
294 dynamic_fmd_fields[normalizedName.split(
".")[1]] = (
297 meta_dict[filename][
"metadata_items"][normalizedName] = (
301 elif regexXAODFileMetaDataAux.match(field.GetTypeName()):
302 meta_dict[filename][
"metadata_items"][
306 ] = field.GetTypeName()
307 elif regexXAODTruthMetaData.match(field.GetTypeName()):
308 meta_dict[filename][
"metadata_items"][
311 .
replace(
"DataVector_",
"DataVector<")
314 elif regexXAODTruthMetaDataAux.match(field.GetTypeName()):
315 meta_dict[filename][
"metadata_items"][
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"][
328 .
replace(
"DataVector_",
"DataVector<")
329 .
replace(
"__Trigger",
">_Trigger")
330 ] = field.GetTypeName()
331 elif regexXAODTriggerMenuJsonAux.match(field.GetTypeName()):
332 meta_dict[filename][
"metadata_items"][
336 ] = field.GetTypeName()
337 elif regexXAODCutBookkeeperContainer.match(field.GetTypeName()):
338 meta_dict[filename][
"metadata_items"][
341 .
replace(
"DataVector_",
"DataVector<")
342 .
replace(
"__CutBookkeeper",
">_CutBookkeeper")
343 ] = field.GetTypeName()
344 elif regexXAODCutBookkeeperContainerAux.match(field.GetTypeName()):
345 meta_dict[filename][
"metadata_items"][
349 ] = field.GetTypeName()
351 meta_dict[filename][
"metadata_items"][
352 field.GetFieldName().
replace(
"Aux:",
"Aux.")
353 ] = field.GetTypeName()
355 if field.GetTypeName()
in classes_with_aux:
357 auxes[field.GetFieldName()] = field.GetTypeName()
361 normalizedName, field.GetTypeName(), meta_filter
365 selected_fields[normalizedName] = (
366 field.GetFieldName(),
371 meta_dict[filename][
"metadata_items"]
374 def _get_aux_base(aux_key: str) -> str:
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_",
"")
382 if key.endswith(
"Aux:"):
384 elif key.endswith(
"Aux"):
387 key = key.strip(
"_:")
390 def _get_main_base(main_key: str) -> str:
393 if main_key.startswith(
"DataVector_xAOD__TriggerMenuJson_v1__"):
394 main_base = main_key.replace(
395 "DataVector_xAOD__TriggerMenuJson_v1__",
""
397 elif main_key.startswith(
"DataVector_xAOD__TriggerMenu_v1__"):
398 main_base = main_key.replace(
399 "DataVector_xAOD__TriggerMenu_v1__",
""
402 elif main_key.startswith(
"xAOD__FileMetaData_v1_"):
403 main_base = main_key.replace(
"xAOD__FileMetaData_v1_",
"")
405 elif main_key.startswith(
"DataVector_xAOD__TruthMetaData_v1__"):
406 main_base = main_key.replace(
407 "DataVector_xAOD__TruthMetaData_v1__",
""
411 def _find_associated_pairs(auxes: dict) -> list[tuple[str, str]]:
416 aux_map[_get_aux_base(k)] = k
420 base = _get_main_base(k)
426 for base, aux_key
in aux_map.items():
428 pairs.append((aux_key, main_map[base]))
432 pair: tuple[str, str], auxes: dict, meta_filter: dict
437 for k, v
in trigger_menu_json_map.items()
441 .
replace(
"DataVector_",
"DataVector<")
442 .
replace(
"__Trigger",
">_Trigger")
449 key.replace(
"xAOD__",
"xAOD::")
450 if key.count(
"_") <= 1
451 else key.replace(
"xAOD__",
"xAOD::").rsplit(
"_", 2)[0]
459 .
replace(
"DataVector_",
"DataVector<")
460 .
replace(
"__Trigger",
">_Trigger")
468 for pair
in _find_associated_pairs(auxes)
469 if _keep_pair(pair, auxes, meta_filter)
474 regexXAODTriggerMenuJsonAux.match(auxes[pair[0]])
475 for pair
in selected_pairs
479 for pair
in selected_pairs
480 if not regexXAODTriggerMenuAux.match(auxes[pair[0]])
483 read_dynamic_fmd = any(
484 "FileMetaData" in pair[0]
for pair
in selected_pairs
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)
490 fields_to_read.update(dynamic_fmd_fields.values())
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)))
498 reader = ROOT.RNTupleReader.Open(ROOT.std.move(model), md)
499 entry = reader.CreateEntry()
500 reader.LoadEntry(0, entry)
503 for normalizedName, (field_name, type_name)
in sorted(
504 selected_fields.items(),
505 key=
lambda item: regexEventStreamInfo.match(item[1][1])
is None,
512 msg.warning(f
"missing type {type_name}")
514 meta_dict[filename][normalizedName] = value
516 regexEventStreamInfo.match(type_name)
518 and len(value.get(
"runNumbers", [])) == 1
520 _gbl_run = value[
"runNumbers"][0]
521 msg.debug(
"Found RunNumber in EventStreamInfo: %d", _gbl_run)
523 dynamic_fmd_items = {}
525 for name, field_name
in dynamic_fmd_fields.items():
527 if name.startswith(
"is"):
529 value = value !=
"\x00"
530 dynamic_fmd_items[name] = value
532 for pair
in selected_pairs:
539 if "TriggerMenu" in pair[0]:
540 if "RAWTriggerMenuJson" in return_obj:
543 if pair[0].startswith(
"Trigger")
544 else trigger_menu_json_map[pair[0]]
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"][
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)
573 .
replace(
"DataVector_",
"DataVector<")
581 elif pair == (
"CutBookkeepersAux:",
"CutBookkeepers"):
582 meta_dict[filename][
"CutBookkeepers"] = return_obj
584 msg.debug(f
"Read metadata from RNTuple: {meta_dict[filename]}")
590 metadata_tree = current_file.Get(
'MetaData')
592 metadata_branches = metadata_tree.GetListOfBranches()
593 nr_of_branches = metadata_branches.GetEntriesFast()
596 meta_dict[filename][
'metadata_items'] = {}
601 persistent_instances = {}
602 dynamic_fmd_items = {}
606 metadata_tree.SetBranchStatus(
"*",
False)
608 for i
in range(0, nr_of_branches):
609 branch = metadata_branches.At(i)
610 name = branch.GetName()
611 if name ==
'index_ref':
615 class_name = branch.GetClassName()
617 if regexIOVMetaDataContainer.match(class_name):
618 name = name.replace(
'IOVMetaDataContainer_p1_',
'').
replace(
'_',
'/')
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'
631 type_name = class_name
634 type_name = branch.GetListOfLeaves()[0].GetTypeName()
637 meta_dict[filename][
'metadata_items'][name] = type_name
639 if len(meta_filter) > 0:
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
655 if 'CutBookkeepers' in name
and name
not in [
'CutBookkeepers',
'CutBookkeepersAux.']:
659 metadata_tree.SetBranchStatus(f
"{name}*",
True)
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()
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()
696 if name
in persistent_instances:
697 branch.SetAddress(ROOT.AddressOf(persistent_instances[name]))
700 dynamicFMD = regexXAODFileMetaDataAuxDyn.match(name)
702 dynamicName = dynamicFMD.group().
split(
'.')[-1]
703 dynamicType = regex_cppname.match(class_name)
706 dynamic_fmd_items[dynamicName] = ROOT.std.string()
707 branch.SetAddress(ROOT.AddressOf(dynamic_fmd_items[dynamicName]))
709 dynamic_fmd_items[dynamicName] =
None
712 metadata_tree.GetEntry(0)
715 for key
in dynamic_fmd_items:
716 if dynamic_fmd_items[key]
is None:
718 if key.startswith(
"is"):
720 dynamic_fmd_items[key] = getattr(metadata_tree, key) !=
'\x00'
723 dynamic_fmd_items[key] = getattr(metadata_tree, key)
724 except AttributeError:
729 dynamic_fmd_items[key] = str(dynamic_fmd_items[key])
733 meta_dict[filename] = {}
736 for key, obj
in persistent_instances.items():
737 if key.startswith(
'EventStreamInfo'):
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)
744 for name, content
in persistent_instances.items():
746 if hasattr(content,
'm_folderName'):
747 key = content.m_folderName
750 has_r3_trig_meta = (
'TriggerMenuJson_HLT' in persistent_instances
or 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT' in persistent_instances)
752 if key.startswith(
'TriggerMenuJson_')
and not key.endswith(
'Aux.'):
753 aux = persistent_instances[key+
'Aux.']
754 elif key.startswith(
'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_')
and not key.endswith(
'Aux.'):
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:
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:
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.':
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.':
777 elif 'Menu' in key
and key.endswith(
'Aux.'):
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']
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)
803 meta_dict[filename][key] = return_obj
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")
816 msg.debug(f
"{meta_dict[filename]['nentries']=}")
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')
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:
835 f
"Found multiple values for {key}: {value}. "
836 "Looking for possible duplicates."
841 unique_amitags =
set()
842 for amitags
in unique_values:
844 "_".join([tag
for tag
in amitags.split(
"_")
if tag])
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:
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:
860 value.insert(0,list(unique_amitags)[0])
861 elif key ==
"beam_energy":
863 unique_energies =
set()
864 for energy
in unique_values:
869 energy = float(energy)
872 unique_energies.add(energy)
873 if len(unique_energies) == 1:
876 elif key
in [
"AtlasRelease",
"IOVDbGlobalTag",
"AODFixVersion",
"randomSeed"]:
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]}"
886 f
"{key} from /TagInfo contains more than 1 unique value: {value}"
889 meta_dict[filename][
'/TagInfo'][key] = value[0]
892 promote = mode ==
'lite' or mode ==
'peeker'
906 if isinstance(collectionTree, ROOT.TTree):
908 (str(b.GetClassName()), str(b.GetName()))
for b
in collectionTree.GetListOfBranches()
910 if normalize_type_names:
914 elif isRNTuple(eventData := current_file.Get(PoolOpts.RNTupleNames.EventData)):
916 eventDataReader = ROOT.RNTupleReader.Open(eventData)
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')
924 if normalize_type_names:
928 if normalize_type_names:
931 meta_dict[filename][
'itemList'] = item_list
934 elif current_file_type ==
'BS':
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))
943 bs = eformat.istream(filename)
944 meta_dict[filename][
'nentries'] = bs.total_events
947 data_reader = eformat.EventStorage.pickDataReader(filename)
948 assert data_reader,
'problem picking a data reader for file [%s]' % filename
951 meta_dict[filename][
'auto_flush'] = 1
953 if hasattr(data_reader,
'GUID'):
954 meta_dict[filename][
'file_guid'] = data_reader.GUID()
957 meta_dict[filename][
'file_comp_alg'] = 1
958 meta_dict[filename][
'file_comp_level'] = 1
966 for md
in data_reader.freeMetaDataStrings():
967 if md.startswith(
'Event type:'):
971 v.append(
'IS_SIMULATION')
978 v.append(
'IS_TESTBEAM')
980 if 'is physics' in md:
981 v.append(
'IS_PHYSICS')
983 v.append(
'IS_CALIBRATION')
985 bs_metadata[k] = tuple(v)
987 elif md.startswith(
'GeoAtlas:'):
989 v = md.split(
'GeoAtlas:')[1].
strip()
992 elif md.startswith(
'IOVDbGlobalTag:'):
994 v = md.split(
'IOVDbGlobalTag:')[1].
strip()
998 k, v = md.split(
'=', 1)
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()
1007 beamTypeNbr= data_reader.beamType()
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'
1016 bs_metadata[
'beamEnergy'] = data_reader.beamEnergy()
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)
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)
1031 if not data_reader.good():
1033 meta_dict[filename][
'runNumbers'].append(bs_metadata.get(
'run_number', 0))
1034 meta_dict[filename][
'lumiBlockNumbers'].append(bs_metadata.get(
'LumiBlock', 0))
1036 msg.debug(f
"{meta_dict[filename]=}")
1037 msg.debug(f
"{len(bs)=}")
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())]
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()]
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)
1058 msg.debug(f
"{meta_dict[filename]=}")
1060 msg.warning(f
"Event-less BS {filename=}, will not read metadata information from the first event")
1063 if len(bs_metadata.get(
'eventTypes',
'')) == 0:
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')
1072 evt_type.append(
'Unknown')
1074 meta_dict[filename][
'eventTypes'] = evt_type
1077 meta_dict[filename][
'bs_metadata'] = bs_metadata
1081 msg.error(
'Unknown filetype for {0} - there is no metadata interface for type {1}'.format(filename, current_file_type))