71 unique_tag_info_values = True, ignoreNonExistingLocalFiles=False):
72 """
73 This tool is independent of Athena framework and returns the metadata from a given file.
74 :param filenames: the input file from which metadata needs to be extracted.
75 :param file_type: the type of file. POOL or BS (bytestream: RAW, DRAW) files.
76 :param mode: if true, will return all metadata associated with the filename. By default, is false and this will
77 return a "tiny" version which have only the following keys: 'file_guid', 'file_size', 'file_type', 'nentries'.
78 :return: a dictionary of metadata for the given input file.
79 """
80
81
82 global _gbl_mode, _gbl_run
83 _gbl_mode = mode
84 _gbl_run = None
85
86 from RootUtils import PyROOTFixes
87
88
89 if isinstance(filenames, str):
90 filenames = [filenames]
91
92
93 if file_type is not None:
94 if file_type not in ('POOL', 'BS'):
95 raise NameError('Allowed values for \'file_type\' parameter are: "POOL" or "BS": you provided "' + file_type + '"')
96 else:
97 msg.info('Forced file_type: {0}'.format(file_type))
98
99
100 if mode not in ('tiny', 'lite', 'full', 'peeker', 'iov'):
101 raise NameError('Allowed values for "mode" parameter are: "tiny", "lite", "peeker", "iov" or "full"')
102
103 if meta_key_filter is None:
104 meta_key_filter = []
105
106
107 if not isGaudiEnv():
108 if mode in ('full', 'iov'):
109 raise NameError('The following modes are not available in AnalysisBase: "iov" and "full"')
110
111 msg.info('Current mode used: {0}'.format(mode))
112 msg.info('Current filenames: {0}'.format(filenames))
113
114 if mode != 'full' and mode !='iov' and len(meta_key_filter) > 0:
115 raise NameError('It is possible to use the meta_key_filter option only for full mode')
116 if meta_key_filter:
117 msg.info('Filter used: {0}'.format(meta_key_filter))
118
119
120 meta_dict = {}
121
122
123 for filename in filenames:
124 meta_dict[filename] = {}
125 current_file_type = None
126
127 _gbl_run = None
128
129 if not file_type:
130 if os.path.isfile(filename):
131
132 if ignoreNonExistingLocalFiles and not regex_URI_scheme.match(filename) and gSystem.AccessPathName(filename):
133 msg.warning('Ignoring not accessible file: {}'.format(filename))
134 continue
135
136 with open(filename, 'rb') as binary_file:
137 magic_file = binary_file.read(4)
138
139 if magic_file == 'root' or magic_file == b'root':
140 current_file_type = 'POOL'
141 meta_dict[filename]['file_type'] = 'POOL'
142
143 elif Project.determine() in (
144 Project.AnalysisBase, Project.AthAnalysis):
145 raise RuntimeError(
146 f"{filename} is not a ROOT file, assumed bytestream"
147 ", this is not supported in Analysis releases")
148 else:
149 current_file_type = 'BS'
150 meta_dict[filename]['file_type'] = 'BS'
151
152
153 meta_dict[filename]['file_size'] = os.path.getsize(filename)
154
155
156 else:
157 if regex_BS_files.match(filename):
158 current_file_type = 'BS'
159 meta_dict[filename]['file_type'] = 'BS'
160 else:
161 current_file_type = 'POOL'
162 meta_dict[filename]['file_type'] = 'POOL'
163
164
165 meta_dict[filename]['file_size'] = None
166
167 else:
168 current_file_type = file_type
169
170
171 if current_file_type == 'POOL':
172
173 if ignoreNonExistingLocalFiles and not regex_URI_scheme.match(filename) and gSystem.AccessPathName(filename):
174 msg.warning('Ignoring not accessible file: {}'.format(filename))
175 continue
176
177 import ROOT
178
179 current_file = ROOT.TFile.Open( _get_pfn(filename) )
180
181
182 from PyUtils.PoolFile import PoolOpts
183 collectionTree = current_file.Get(PoolOpts.TTreeNames.EventData)
184 if isinstance(collectionTree, ROOT.TTree):
185 meta_dict[filename]['auto_flush'] = collectionTree.GetAutoFlush()
186
187
188 meta_dict[filename]['file_guid'] = _read_guid(filename)
189
190
191 meta_dict[filename]['file_comp_alg'] = current_file.GetCompressionAlgorithm()
192 meta_dict[filename]['file_comp_level'] = current_file.GetCompressionLevel()
193
194 if (
195 isRNTuple(md:=current_file.Get(PoolOpts.RNTupleNames.MetaData))
196 and mode != "tiny"
197 ):
198 msg.warning(
199 "Reading in-file metadata from RNTuple is currently of limited support"
200 )
201 meta_dict[filename]["metadata_items"] = {}
202
203 try:
204 from ROOT import RNTupleReader
205 except ImportError:
206 from ROOT.Experimental import RNTupleReader
207
208 reader = RNTupleReader.Open(md)
209 entry = reader.CreateEntry()
210 reader.LoadEntry(0, entry)
211 auxes = {}
212 classes_with_aux = {
213 "xAOD::FileMetaData_v1",
214 "xAOD::FileMetaDataAuxInfo_v1",
215 "xAOD::TriggerMenuJsonAuxContainer_v1",
216 "DataVector<xAOD::TriggerMenuJson_v1>",
217 "xAOD::TruthMetaDataAuxContainer_v1",
218 "DataVector<xAOD::TruthMetaData_v1>",
219 "xAOD::CutBookkeeperContainer_v1",
220 "xAOD::CutBookkeeperAuxContainer_v1",
221 "xAOD::LumiBlockRangeAuxContainer_v1",
222 "DataVector<xAOD::LumiBlockRange_v1>",
223 }
224
225 dynamic_fmd_items = {}
226
227 meta_filter = get_meta_filter(mode, meta_key_filter)
228
229 for field in reader.GetDescriptor().GetTopLevelFields():
230 normalizedName = field.GetFieldName()
231 if "index_ref" in normalizedName:
232 continue
233 if regexIOVMetaDataContainer.match(field.GetTypeName()):
234
235
236 normalizedName = (
237 field.GetFieldName()
238 .
replace(
"IOVMetaDataContainer_p1_",
"")
240 )
241 meta_dict[filename]["metadata_items"][normalizedName] = (
242 "IOVMetaDataContainer"
243 )
244 elif regexByteStreamMetadataContainer.match(field.GetTypeName()):
245 meta_dict[filename]["metadata_items"][field.GetFieldName()] = (
246 "ByteStreamMetadataContainer"
247 )
248 elif regexEventStreamInfo.match(field.GetTypeName()):
249 meta_dict[filename]["metadata_items"][field.GetFieldName()] = (
250 "EventStreamInfo"
251 )
252 elif regexXAODFileMetaData.match(field.GetTypeName()):
253 meta_dict[filename]["metadata_items"][
254 field.GetFieldName().
replace(
"xAOD__",
"xAOD::")
255 ] = field.GetTypeName()
256 elif regexXAODFileMetaDataAuxDyn.match(
257 normalizedName := field.GetFieldName()
260 ):
261 result = (
262 False
263 if entry[field.GetFieldName()] == "\x00"
264 else entry[field.GetFieldName()]
265 )
266 dynamic_fmd_items[normalizedName.split(".")[1]] = result
267 meta_dict[filename]["metadata_items"][normalizedName] = (
268 field.GetTypeName()
269 )
270 continue
271 elif regexXAODFileMetaDataAux.match(field.GetTypeName()):
272 meta_dict[filename]["metadata_items"][
273 field.GetFieldName()
276 ] = field.GetTypeName()
277 elif regexXAODTruthMetaData.match(field.GetTypeName()):
278 meta_dict[filename]["metadata_items"][
279 field.GetFieldName()
281 .
replace(
"DataVector_",
"DataVector<")
283 ] = "TruthMetaData"
284 elif regexXAODTruthMetaDataAux.match(field.GetTypeName()):
285 meta_dict[filename]["metadata_items"][
286 field.GetFieldName()
289 ] = field.GetTypeName()
290 elif regexXAODEventFormat.match(field.GetTypeName()):
291 meta_dict[filename]["metadata_items"][
292 field.GetFieldName().
replace(
"xAOD__",
"xAOD::")
293 ] = field.GetTypeName()
294 elif regexXAODTriggerMenuJson.match(field.GetTypeName()):
295 meta_dict[filename]["metadata_items"][
296 field.GetFieldName()
298 .
replace(
"DataVector_",
"DataVector<")
299 .
replace(
"__Trigger",
">_Trigger")
300 ] = field.GetTypeName()
301 elif regexXAODTriggerMenuJsonAux.match(field.GetTypeName()):
302 meta_dict[filename]["metadata_items"][
303 field.GetFieldName()
306 ] = field.GetTypeName()
307 elif regexXAODCutBookkeeperContainer.match(field.GetTypeName()):
308 meta_dict[filename]["metadata_items"][
309 field.GetFieldName()
311 .
replace(
"DataVector_",
"DataVector<")
312 .
replace(
"__CutBookkeeper",
">_CutBookkeeper")
313 ] = field.GetTypeName()
314 elif regexXAODCutBookkeeperContainerAux.match(field.GetTypeName()):
315 meta_dict[filename]["metadata_items"][
316 field.GetFieldName()
319 ] = field.GetTypeName()
320 else:
321 meta_dict[filename]["metadata_items"][
322 field.GetFieldName().
replace(
"Aux:",
"Aux.")
323 ] = field.GetTypeName()
324
325 if field.GetTypeName() in classes_with_aux:
326
327 auxes[field.GetFieldName()] = field.GetTypeName()
328 continue
329
330 if not should_keep_meta(
331 normalizedName, field.GetTypeName(), meta_filter
332 ):
333 continue
334
335 try:
336 meta_dict[filename][normalizedName] = _convert_value(
337 entry[field.GetFieldName()]
338 )
339 except KeyError:
340 msg.warning(f"missing type {field.GetTypeName()}")
341
342 meta_dict[filename]["metadata_items"] = denormalize_metadata_types(
343 meta_dict[filename]["metadata_items"]
344 )
345
346 def _get_aux_base(aux_key: str) -> str:
347
348 key = aux_key
349 key = key.replace("xAOD__TriggerMenuJsonAuxContainer_v1_", "")
350 key = key.replace("xAOD__FileMetaDataAuxInfo_v1_", "")
351 key = key.replace("xAOD__TruthMetaDataAuxContainer_v1_", "")
352
353 if key.endswith("Aux:"):
354 key = key[:-4]
355 elif key.endswith("Aux"):
356 key = key[:-3]
357
358 key = key.strip("_:")
359 return key
360
361 def _get_main_base(main_key: str) -> str:
362 main_base = main_key
363
364 if main_key.startswith("DataVector_xAOD__TriggerMenuJson_v1__"):
365 main_base = main_key.replace(
366 "DataVector_xAOD__TriggerMenuJson_v1__", ""
367 )
368
369 elif main_key.startswith("xAOD__FileMetaData_v1_"):
370 main_base = main_key.replace("xAOD__FileMetaData_v1_", "")
371
372 elif main_key.startswith("DataVector_xAOD__TruthMetaData_v1__"):
373 main_base = main_key.replace(
374 "DataVector_xAOD__TruthMetaData_v1__", ""
375 )
376 return main_base
377
378 def _find_associated_pairs(auxes: dict) -> list[tuple[str, str]]:
379
380 aux_map = {}
381 for k in auxes:
382 if "Aux" in k:
383 aux_map[_get_aux_base(k)] = k
384
385 main_map = {}
386 for k in auxes:
387 base = _get_main_base(k)
388 if base:
389 main_map[base] = k
390
391
392 pairs = []
393 for base, aux_key in aux_map.items():
394 if base in main_map:
395 pairs.append((aux_key, main_map[base]))
396 return pairs
397
398 for pair in _find_associated_pairs(auxes):
399 return_obj = _convert_value(
400 entry[pair[1]],
401 entry[pair[0]],
402 )
403 key = next(
404 (
405 k
406 for k, v in trigger_menu_json_map.items()
407 if v
408 == pair[1]
410 .
replace(
"DataVector_",
"DataVector<")
411 .
replace(
"__Trigger",
">_Trigger")
412 ),
413 auxes[pair[0]],
414 )
415
416 try:
417 key = (
418 key.replace("xAOD__", "xAOD::")
419 if key.count("_") <= 1
420 else key.replace("xAOD__", "xAOD::").rsplit("_", 2)[0]
421 )
422 except IndexError:
423 pass
424
425 if not should_keep_meta(
426 pair[0]
428 .
replace(
"DataVector_",
"DataVector<")
429 .
replace(
"__Trigger",
">_Trigger")
431 key,
432 meta_filter,
433 ):
434 continue
435
436 if "TriggerMenuJson" in pair[0]:
437 if "RAWTriggerMenuJson" in return_obj:
438 key = (
439 pair[1]
440 if pair[0].startswith("Trigger")
441 else trigger_menu_json_map[pair[0]]
442 )
443 meta_dict[filename][key] = return_obj["RAWTriggerMenuJson"]
444 del return_obj["RAWTriggerMenuJson"]
445 if "TriggerConfigInfo" not in meta_dict[filename]:
446 meta_dict[filename]["TriggerConfigInfo"] = {}
447 if "dbkey" in return_obj:
448 meta_dict[filename]["TriggerConfigInfo"][
450 ] = {"key": return_obj["dbkey"], "name": return_obj["name"]}
451 del return_obj["dbkey"]
452 del return_obj["name"]
453 if "TriggerMenu" not in meta_dict[filename]:
454 meta_dict[filename]["TriggerMenu"] = {}
455 meta_dict[filename]["TriggerMenu"].update(return_obj)
456 elif "FileMetaData" in pair[0]:
457 if "FileMetaData" not in meta_dict[filename]:
458 meta_dict[filename]["FileMetaData"] = dynamic_fmd_items
459 meta_dict[filename]["FileMetaData"].update(return_obj)
460 elif "TruthMetaData" in pair[0]:
461 if pair == ("TruthMetaDataAux:", "TruthMetaData"):
462 if "TruthMetaData" not in meta_dict[filename]:
463 meta_dict[filename]["TruthMetaData"] = {}
464 meta_dict[filename]["TruthMetaData"].update(return_obj)
465 else:
466
467 meta_dict[filename][
468 pair[1]
470 .
replace(
"DataVector_",
"DataVector<")
472 ] = {}
473 meta_dict[filename][
474 pair[0]
477 ] = {}
478 elif pair == ("CutBookkeepersAux:", "CutBookkeepers"):
479 meta_dict[filename]["CutBookkeepers"] = return_obj
480
481 msg.debug(f"Read metadata from RNTuple: {meta_dict[filename]}")
482
483 else:
484
485 if mode != 'tiny':
486
487 metadata_tree = current_file.Get('MetaData')
488
489 metadata_branches = metadata_tree.GetListOfBranches()
490 nr_of_branches = metadata_branches.GetEntriesFast()
491
492
493 meta_dict[filename]['metadata_items'] = {}
494
495 meta_filter = get_meta_filter(mode, meta_key_filter)
496
497
498 persistent_instances = {}
499 dynamic_fmd_items = {}
500
501
502 if not isGaudiEnv():
503 metadata_tree.SetBranchStatus("*", False)
504
505 for i in range(0, nr_of_branches):
506 branch = metadata_branches.At(i)
507 name = branch.GetName()
508 if name == 'index_ref':
509
510 continue
511
512 class_name = branch.GetClassName()
513
514 if regexIOVMetaDataContainer.match(class_name):
515 name = name.replace(
'IOVMetaDataContainer_p1_',
'').
replace(
'_',
'/')
516
517 if regexIOVMetaDataContainer.match(class_name):
518 meta_dict[filename]['metadata_items'][name] = 'IOVMetaDataContainer'
519 elif regexByteStreamMetadataContainer.match(class_name):
520 meta_dict[filename]['metadata_items'][name] = 'ByteStreamMetadataContainer'
521 elif regexEventStreamInfo.match(class_name):
522 meta_dict[filename]['metadata_items'][name] = 'EventStreamInfo'
523 elif regexXAODFileMetaData.match(class_name):
524 meta_dict[filename]['metadata_items'][name] = 'FileMetaData'
525 elif regexXAODTruthMetaData.match(class_name):
526 meta_dict[filename]['metadata_items'][name] = 'TruthMetaData'
527 else:
528 type_name = class_name
529 if not type_name:
530 try:
531 type_name = branch.GetListOfLeaves()[0].GetTypeName()
532 except IndexError:
533 pass
534 meta_dict[filename]['metadata_items'][name] = type_name
535
536 if len(meta_filter) > 0:
537 keep = False
538 for filter_key, filter_class in meta_filter.items():
539 if (filter_key.replace('/', '_') in name.replace('/', '_') or filter_key == '*') and fnmatchcase(class_name, filter_class):
540 if 'CutBookkeepers' in filter_key:
541 keep = filter_key == name
542 if keep:
543 break
544 else:
545 keep = True
546 break
547
548 if not keep:
549 continue
550 else:
551
552 if 'CutBookkeepers' in name and name not in ['CutBookkeepers', 'CutBookkeepersAux.']:
553 continue
554
555 if not isGaudiEnv():
556 metadata_tree.SetBranchStatus(f"{name}*", True)
557
558
559 if regexEventStreamInfo.match(class_name):
560 if class_name.endswith('_p1'):
561 persistent_instances[name] = ROOT.EventStreamInfo_p1()
562 elif class_name.endswith('_p2'):
563 persistent_instances[name] = ROOT.EventStreamInfo_p2()
564 else:
565 persistent_instances[name] = ROOT.EventStreamInfo_p3()
566 elif regexIOVMetaDataContainer.match(class_name):
567 persistent_instances[name] = ROOT.IOVMetaDataContainer_p1()
568 elif regexXAODEventFormat.match(class_name):
569 persistent_instances[name] = ROOT.xAOD.EventFormat_v1()
570 elif regexXAODTriggerMenu.match(class_name) and _check_project() not in ['AthGeneration']:
571 persistent_instances[name] = ROOT.xAOD.TriggerMenuContainer_v1()
572 elif regexXAODTriggerMenuAux.match(class_name) and _check_project() not in ['AthGeneration']:
573 persistent_instances[name] = ROOT.xAOD.TriggerMenuAuxContainer_v1()
574 elif regexXAODTriggerMenuJson.match(class_name) and _check_project() not in ['AthGeneration']:
575 persistent_instances[name] = ROOT.xAOD.TriggerMenuJsonContainer_v1()
576 elif regexXAODTriggerMenuJsonAux.match(class_name) and _check_project() not in ['AthGeneration']:
577 persistent_instances[name] = ROOT.xAOD.TriggerMenuJsonAuxContainer_v1()
578 elif regexXAODCutBookkeeperContainer.match(class_name):
579 persistent_instances[name] = ROOT.xAOD.CutBookkeeperContainer_v1()
580 elif regexXAODCutBookkeeperContainerAux.match(class_name):
581 persistent_instances[name] = ROOT.xAOD.CutBookkeeperAuxContainer_v1()
582 elif regexXAODFileMetaData.match(class_name):
583 persistent_instances[name] = ROOT.xAOD.FileMetaData_v1()
584 elif regexXAODFileMetaDataAux.match(class_name):
585 persistent_instances[name] = ROOT.xAOD.FileMetaDataAuxInfo_v1()
586 elif regexXAODTruthMetaData.match(class_name):
587 persistent_instances[name] = ROOT.xAOD.TruthMetaDataContainer_v1()
588 elif regexXAODTruthMetaDataAux.match(class_name):
589 persistent_instances[name] = ROOT.xAOD.TruthMetaDataAuxContainer_v1()
590
591 if name in persistent_instances:
592 branch.SetAddress(ROOT.AddressOf(persistent_instances[name]))
593
594
595 dynamicFMD = regexXAODFileMetaDataAuxDyn.match(name)
596 if dynamicFMD:
597 dynamicName = dynamicFMD.group().
split(
'.')[-1]
598 dynamicType = regex_cppname.match(class_name)
599 if dynamicType:
600
601 dynamic_fmd_items[dynamicName] = ROOT.std.string()
602 branch.SetAddress(ROOT.AddressOf(dynamic_fmd_items[dynamicName]))
603 else:
604 dynamic_fmd_items[dynamicName] = None
605
606
607 metadata_tree.GetEntry(0)
608
609
610 for key in dynamic_fmd_items:
611 if dynamic_fmd_items[key] is None:
612 try:
613 if key.startswith("is"):
614
615 dynamic_fmd_items[key] = getattr(metadata_tree, key) != '\x00'
616 else:
617
618 dynamic_fmd_items[key] = getattr(metadata_tree, key)
619 except AttributeError:
620
621 pass
622 else:
623
624 dynamic_fmd_items[key] = str(dynamic_fmd_items[key])
625
626
627 if meta_key_filter:
628 meta_dict[filename] = {}
629
630
631 for key, obj in persistent_instances.items():
632 if key.startswith('EventStreamInfo'):
633 data = _convert_value(obj, None)
634 if data and 'runNumbers' in data and len(data['runNumbers']) == 1:
635 _gbl_run = data['runNumbers'][0]
636 msg.debug("Found RunNumber in EventStreamInfo: %d", _gbl_run)
637
638
639 for name, content in persistent_instances.items():
640 key = name
641 if hasattr(content, 'm_folderName'):
642 key = content.m_folderName
643
644
645 has_r3_trig_meta = ('TriggerMenuJson_HLT' in persistent_instances or 'DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_HLT' in persistent_instances)
646 aux = None
647 if key.startswith('TriggerMenuJson_') and not key.endswith('Aux.'):
648 aux = persistent_instances[key+'Aux.']
649 elif key.startswith('DataVector<xAOD::TriggerMenuJson_v1>_TriggerMenuJson_') and not key.endswith('Aux.'):
650 menuPart = key.split('_')[-1]
651 aux = persistent_instances['xAOD::TriggerMenuJsonAuxContainer_v1_TriggerMenuJson_'+menuPart+'Aux.']
652 elif key == 'TriggerMenu' and 'TriggerMenuAux.' in persistent_instances and not has_r3_trig_meta:
653 aux = persistent_instances['TriggerMenuAux.']
654 elif key == 'DataVector<xAOD::TriggerMenu_v1>_TriggerMenu' and 'xAOD::TriggerMenuAuxContainer_v1_TriggerMenuAux.' in persistent_instances and not has_r3_trig_meta:
655 aux = persistent_instances['xAOD::TriggerMenuAuxContainer_v1_TriggerMenuAux.']
656 elif (key == 'CutBookkeepers'
657 and 'CutBookkeepersAux.' in persistent_instances):
658 aux = persistent_instances['CutBookkeepersAux.']
659 elif key == 'CutBookkeepersAux.':
660 continue
661 elif (key == 'FileMetaData'
662 and 'FileMetaDataAux.' in persistent_instances):
663 aux = persistent_instances['FileMetaDataAux.']
664 elif (key == 'xAOD::FileMetaData_v1_FileMetaData'
665 and 'xAOD::FileMetaDataAuxInfo_v1_FileMetaDataAux.' in persistent_instances):
666 aux = persistent_instances['xAOD::FileMetaDataAuxInfo_v1_FileMetaDataAux.']
667 elif (key == 'TruthMetaData'
668 and 'TruthMetaDataAux.' in persistent_instances):
669 aux = persistent_instances['TruthMetaDataAux.']
670 elif key == 'TruthMetaDataAux.':
671 continue
672 elif 'Menu' in key and key.endswith('Aux.'):
673 continue
674
675 return_obj = _convert_value(content, aux)
676
677 if 'TriggerMenuJson' in key or ('TriggerMenu' in key and not has_r3_trig_meta):
678 if 'RAWTriggerMenuJson' in return_obj:
679 meta_dict[filename][key] = return_obj['RAWTriggerMenuJson']
680 del return_obj['RAWTriggerMenuJson']
681 if 'TriggerConfigInfo' not in meta_dict[filename]:
682 meta_dict[filename]['TriggerConfigInfo'] = {}
683 if 'dbkey' in return_obj:
684 meta_dict[filename]['TriggerConfigInfo'][key.split('_')[-1]] = {
685 'key' : return_obj['dbkey'],
686 'name': return_obj['name']
687 }
688 del return_obj['dbkey']
689 del return_obj['name']
690 if 'TriggerMenu' not in meta_dict[filename]:
691 meta_dict[filename]['TriggerMenu'] = {}
692 meta_dict[filename]['TriggerMenu'].update(return_obj)
693 elif "FileMetaData" in key:
694 if "FileMetaData" not in meta_dict[filename]:
695 meta_dict[filename]["FileMetaData"] = dynamic_fmd_items
696 meta_dict[filename]["FileMetaData"].update(return_obj)
697 else:
698 meta_dict[filename][key] = return_obj
699
700 try:
701
702 esi_dict = next(key for key, value in meta_dict[filename].items()
703 if isinstance(value, dict) and "numberOfEvents" in value and
704 meta_dict[filename]["metadata_items"][key] == "EventStreamInfo")
705 msg.debug(f"{esi_dict=}")
706 meta_dict[filename]["nentries"] = meta_dict[filename][esi_dict]["numberOfEvents"]
707 except StopIteration as err:
708 msg.debug(f"Caught {err=}, {type(err)=}, falling back on opening the DataHeader"
709 " Container to read the number of entries")
710 meta_dict[filename]['nentries'] = dataheader_nentries(current_file)
711 msg.debug(f"{meta_dict[filename]['nentries']=}")
712
713 if unique_tag_info_values and mode=='iov':
714 unique_tag_info_values = False
715 msg.info('disabling "unique_tag_info_values" option for "iov" mode')
716
717
718
719
720
721
722 if unique_tag_info_values:
723 msg.info('MetaReader is called with the parameter "unique_tag_info_values" set to True. '
724 'This is a workaround to remove all duplicate values from "/TagInfo" key')
725 if '/TagInfo' in meta_dict[filename]:
726 for key, value in meta_dict[filename]['/TagInfo'].items():
727 if isinstance(value, list) and value:
728 if len(unique_values :=
set(value)) > 1:
729 msg.warning(
730 f"Found multiple values for {key}: {value}. "
731 "Looking for possible duplicates."
732 )
733 maybe_ok = False
734 if key == "AMITag":
735
736 unique_amitags =
set()
737 for amitags in unique_values:
738 unique_amitags.add(
739 "_".join([tag for tag in amitags.split("_") if tag])
740 )
741
742
743 parent_tags = []
744 for atag in unique_amitags:
745 if any(atag+'_' in x for x in unique_amitags if x != atag):
746 parent_tags += [atag]
747 for atag in parent_tags:
748
749 if len(unique_amitags)>1:
750 msg.warning(f"Removing parent AMI tag {atag}")
751 unique_amitags.remove(atag)
752 if len(unique_amitags) == 1:
753 maybe_ok = True
754
755 value.insert(0,list(unique_amitags)[0])
756 elif key == "beam_energy":
757
758 unique_energies =
set()
759 for energy in unique_values:
760 try:
761 energy = int(energy)
762 except ValueError:
763 try:
764 energy = float(energy)
765 except ValueError:
766 pass
767 unique_energies.add(energy)
768 if len(unique_energies) == 1:
769 maybe_ok = True
770 elif key in ["AtlasRelease", "IOVDbGlobalTag", "AODFixVersion"]:
771 maybe_ok = True
772 if maybe_ok:
773 msg.warning(
774 f"Multiple values for {key} may mean the same, or "
775 "the input file was produced in multi-step job. "
776 f"Ignoring all but the first entry: {key} = {value[0]}"
777 )
778 else:
779 raise ValueError(
780 f"{key} from /TagInfo contains more than 1 unique value: {value}"
781 )
782
783 meta_dict[filename]['/TagInfo'][key] = value[0]
784
785 if promote is None:
786 promote = mode == 'lite' or mode == 'peeker'
787
788
789 if mode == 'lite':
790 meta_dict = make_lite(meta_dict)
791
792 if mode == 'peeker':
793 meta_dict = make_peeker(meta_dict)
794
795 if promote:
796 meta_dict = promote_keys(meta_dict, mode)
797
798
799 if not isGaudiEnv():
800 if isinstance(collectionTree, ROOT.TTree):
801 meta_dict[filename]['itemList'] = [ (b.GetClassName(), b.GetName()) for b in collectionTree.GetListOfBranches() ]
802
803
804 elif current_file_type == 'BS':
805
806 if ignoreNonExistingLocalFiles and not regex_URI_scheme.match(filename) and not os.path.isfile(filename):
807 msg.warning('Ignoring not accessible file: {}'.format(filename))
808 continue
809
810 import eformat
811
812
813 bs = eformat.istream(filename)
814 meta_dict[filename]['nentries'] = bs.total_events
815
816
817 data_reader = eformat.EventStorage.pickDataReader(filename)
818 assert data_reader, 'problem picking a data reader for file [%s]' % filename
819
820
821 meta_dict[filename]['auto_flush'] = 1
822
823 if hasattr(data_reader, 'GUID'):
824 meta_dict[filename]['file_guid'] = data_reader.GUID()
825
826
827 meta_dict[filename]['file_comp_alg'] = 1
828 meta_dict[filename]['file_comp_level'] = 1
829
830
831
832
833 if mode != "tiny":
834 bs_metadata = {}
835
836 for md in data_reader.freeMetaDataStrings():
837 if md.startswith('Event type:'):
838 k = 'eventTypes'
839 v = []
840 if 'is sim' in md:
841 v.append('IS_SIMULATION')
842 else:
843 v.append('IS_DATA')
844
845 if 'is atlas' in md:
846 v.append('IS_ATLAS')
847 else:
848 v.append('IS_TESTBEAM')
849
850 if 'is physics' in md:
851 v.append('IS_PHYSICS')
852 else:
853 v.append('IS_CALIBRATION')
854
855 bs_metadata[k] = tuple(v)
856
857 elif md.startswith('GeoAtlas:'):
858 k = 'geometry'
859 v = md.split(
'GeoAtlas:')[1].
strip()
860 bs_metadata[k] = v
861
862 elif md.startswith('IOVDbGlobalTag:'):
863 k = 'conditions_tag'
864 v = md.split(
'IOVDbGlobalTag:')[1].
strip()
865 bs_metadata[k] = v
866
867 elif '=' in md:
868 k, v = md.split('=', 1)
869 bs_metadata[k] = v
870
871 bs_metadata['detectorMask'] = data_reader.detectorMask()
872 bs_metadata['runNumbers'] = data_reader.runNumber()
873 bs_metadata['lumiBlockNumbers'] = data_reader.lumiblockNumber()
874 bs_metadata['projectTag'] = data_reader.projectTag()
875 bs_metadata['stream'] = data_reader.stream()
876
877 beamTypeNbr= data_reader.beamType()
878
879
880
881
882 if (beamTypeNbr==0): bs_metadata['beamType'] = 'cosmics'
883 elif (beamTypeNbr==1 or beamTypeNbr==2): bs_metadata['beamType'] = 'collisions'
884 else: bs_metadata['beamType'] = 'unknown'
885
886 bs_metadata['beamEnergy'] = data_reader.beamEnergy()
887
888 meta_dict[filename]['eventTypes'] = bs_metadata.get('eventTypes', [])
889 meta_dict[filename]['GeoAtlas'] = bs_metadata.get('geometry', None)
890 meta_dict[filename]['conditions_tag'] = bs_metadata.get('conditions_tag', None)
891 meta_dict[filename]['project_name'] = bs_metadata.get('projectTag', None)
892
893
894 meta_dict[filename]['detectorMask'] = [bs_metadata.get('detectorMask', None)]
895 meta_dict[filename]['runNumbers'] = [bs_metadata.get('runNumbers', None)]
896 meta_dict[filename]['lumiBlockNumbers'] = [bs_metadata.get('lumiBlockNumbers', None)]
897 meta_dict[filename]['beam_type'] = bs_metadata.get('beamType', None)
898 meta_dict[filename]['beam_energy'] = bs_metadata.get('beamEnergy', None)
899 meta_dict[filename]['stream'] = bs_metadata.get('stream', None)
900
901 if not data_reader.good():
902
903 meta_dict[filename]['runNumbers'].append(bs_metadata.get('run_number', 0))
904 meta_dict[filename]['lumiBlockNumbers'].append(bs_metadata.get('LumiBlock', 0))
905
906 msg.debug(f"{meta_dict[filename]=}")
907 msg.debug(f"{len(bs)=}")
908 if len(bs):
909 evt = bs[0]
910 try:
911 evt.check()
912 meta_dict[filename]['processingTags'] = [tag.name for tag in evt.stream_tag()]
913 meta_dict[filename]['evt_number'] = [evt.global_id()]
914 meta_dict[filename]['run_type'] = [eformat.helper.run_type2string(evt.run_type())]
915
916
917 if meta_dict[filename]['lumiBlockNumbers'] == [0]:
918 msg.debug('Taking the luminosity block info from the first event (%i)', evt.lumi_block())
919 meta_dict[filename]['lumiBlockNumbers'] = [evt.lumi_block()]
920
921
922 if meta_dict[filename]['runNumbers'] == [0]:
923 msg.debug('Taking the run number info from the first event (%i)', evt.run_no())
924 meta_dict[filename]['runNumbers'] = [evt.run_no()]
925 except RuntimeError as err:
926 msg.error("Issue while reading the first event of BS file %r: %r", filename, err)
927 else:
928 msg.debug(f"{meta_dict[filename]=}")
929 else:
930 msg.warning(f"Event-less BS {filename=}, will not read metadata information from the first event")
931
932
933 if len(bs_metadata.get('eventTypes', '')) == 0:
934 evt_type = ['IS_DATA', 'IS_ATLAS']
935 if bs_metadata.get('stream', '').startswith('physics_'):
936 evt_type.append('IS_PHYSICS')
937 elif bs_metadata.get('stream', '').startswith('calibration_'):
938 evt_type.append('IS_CALIBRATION')
939 elif bs_metadata.get('projectTag', '').endswith('_calib'):
940 evt_type.append('IS_CALIBRATION')
941 else:
942 evt_type.append('Unknown')
943
944 meta_dict[filename]['eventTypes'] = evt_type
945
946 if mode == 'full':
947 meta_dict[filename]['bs_metadata'] = bs_metadata
948
949
950 else:
951 msg.error('Unknown filetype for {0} - there is no metadata interface for type {1}'.format(filename, current_file_type))
952 return None
953
954 return meta_dict
955
956
std::string replace(std::string s, const std::string &s2, const std::string &s3)