Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-28 08:27:00

0001 #!/usr/bin/env python3
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 # Branches with known dangling collectionID references. These are still
0014 # reported (as KNOWN) but do not contribute to the non-zero exit code.
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         # RNTuple: nested record.
0051         arr = a[group].collectionID
0052     else:
0053         # TTree: dotted flat field.
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     # Collect unique relation group names, e.g. '_TOFBarrelClusterHits_hits'.
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()