File indexing completed on 2026-07-28 08:27:00
0001
0002 """Verify that every collectionID referenced by relation branches
0003 (_<Coll>_<relation>.collectionID) in the 'events' tree exists in the
0004 podio_metadata events CollectionTypeInfo table."""
0005 import sys
0006 import re
0007 import argparse
0008 import numpy as np
0009 import awkward as ak
0010 import uproot
0011
0012
0013
0014
0015 KNOWN_ISSUES = {
0016 "_DRICHAerogelIrtCherenkovParticleID_chargedParticle",
0017 "_DRICHGasIrtCherenkovParticleID_chargedParticle",
0018 "_DRICHRawHitsAssociations_simHit",
0019 "_DRICHRawHitsLinks_to",
0020 "_EcalBarrelImagingClusters_clusters",
0021 "_EcalBarrelTruthClusters_clusters",
0022 "_EcalEndcapNClusters_particleIDs",
0023 "_EcalEndcapNExpectedClusters_particleIDs",
0024 "_EcalEndcapNRemnantClusters_particleIDs",
0025 "_HcalEndcapPInsertClusters_hits",
0026 "_HcalEndcapPInsertRemnantClusters_hits",
0027 "_RICHEndcapNRawHitsAssociations_simHit",
0028 "_RICHEndcapNRawHitsLinks_to",
0029 "_TaggerTrackerM1L0ClusterPositions_hits",
0030 "_TaggerTrackerM1L1ClusterPositions_hits",
0031 "_TaggerTrackerM1L2ClusterPositions_hits",
0032 "_TaggerTrackerM1L3ClusterPositions_hits",
0033 "_TaggerTrackerM2L0ClusterPositions_hits",
0034 "_TaggerTrackerM2L1ClusterPositions_hits",
0035 "_TaggerTrackerM2L2ClusterPositions_hits",
0036 "_TaggerTrackerM2L3ClusterPositions_hits",
0037 "_TOFBarrelClusterHits_hits",
0038 "_TOFEndcapClusterHits_hits",
0039 }
0040
0041
0042 def read_collection_id_field(obj, group):
0043 """Read the collectionID sub-field of a podio relation group.
0044
0045 Works for both TTree- and RNTuple-backed containers. Returns a flat
0046 numpy array of uint32 values.
0047 """
0048 a = obj[group].arrays()
0049 if group in a.fields:
0050
0051 arr = a[group].collectionID
0052 else:
0053
0054 arr = a[f"{group}.collectionID"]
0055 return np.asarray(ak.flatten(arr, axis=None), dtype=np.uint32)
0056
0057
0058 def main():
0059 ap = argparse.ArgumentParser()
0060 ap.add_argument("file", help="podio ROOT file")
0061 args = ap.parse_args()
0062
0063 f = uproot.open(args.file)
0064 events = f["events"]
0065 meta = f["podio_metadata"]
0066
0067 known_ids = set(int(x) for x in read_collection_id_field(meta, "events___CollectionTypeInfo"))
0068
0069
0070 pattern = re.compile(r"^(_[^/]+_[^/.]+)(?:/\1)?\.collectionID$")
0071 groups = sorted({m.group(1) for k in events.keys() for m in [pattern.match(k)] if m})
0072
0073 errors = 0
0074 for group in groups:
0075 ids = read_collection_id_field(events, group)
0076 unique_ids = np.unique(ids)
0077 unknown = [int(i) for i in unique_ids if int(i) not in (0, 0xFFFFFFFF) and int(i) not in known_ids]
0078 if unknown:
0079 if group in KNOWN_ISSUES:
0080 print(f"KNOWN: branch {group} references unknown collectionID(s): {unknown}")
0081 else:
0082 errors += 1
0083 print(f"ERROR: branch {group} references unknown collectionID(s): {unknown}")
0084
0085 print(f"\nChecked {len(groups)} relation branches; {errors} unexpected error(s) (known issues excluded).")
0086 sys.exit(1 if errors else 0)
0087
0088
0089 if __name__ == "__main__":
0090 main()