File indexing completed on 2026-04-25 08:28:59
0001
0002 """Extract geometry_config and gun parameters from podio runs frame, print as JSON.
0003
0004 Usage:
0005 parse_podio_metadata.py <edm4hep.root> [--gun] [--no-beam]
0006
0007 --gun Also extract gun parameters (for single particle runs)
0008 --no-beam Omit beam energy and ion species fields (for background runs)
0009 """
0010
0011 import sys
0012 import math
0013 import json
0014 import re
0015 import podio.root_io
0016
0017 from shared_utils import detect_generator, detect_q2, detect_pwg, detect_dsc
0018
0019
0020 def rad_to_deg(r):
0021 return round(float(r) * 180 / math.pi, 2)
0022
0023
0024 def get_str(params, key):
0025 """Return string value for key, or None if not set or stored as 'None'."""
0026 v = params.get['std::string'](key)
0027 if not v.has_value():
0028 return None
0029 s = v.value()
0030 return None if s == "None" else s
0031
0032
0033 include_gun = "--gun" in sys.argv
0034 no_beam = "--no-beam" in sys.argv
0035 rootfile = next(a for a in sys.argv[1:] if not a.startswith("--"))
0036
0037 reader = podio.root_io.Reader(rootfile)
0038 frame = next(iter(reader.get("runs")))
0039 params = frame.get_parameters()
0040
0041 result = {}
0042
0043
0044 input_files = get_str(params, "inputFiles")
0045 if input_files:
0046 input_path = input_files.strip("[]'\" ")
0047 result["generator"] = detect_generator(input_path, is_single=include_gun)
0048 if not include_gun and not no_beam:
0049 result["requester_pwg"] = detect_pwg(input_path)
0050 q2_min, q2_max = detect_q2(input_path)
0051 if q2_min is not None:
0052 result["q2_min_gev2"] = q2_min
0053 if q2_max is not None:
0054 result["q2_max_gev2"] = q2_max
0055
0056
0057 bg_files = get_str(params, "hepmc_merger_background_files")
0058 result["is_background_mixed"] = bool(bg_files and bg_files.strip() not in ("", "None", "[]"))
0059
0060
0061 if input_files:
0062 dsc = detect_dsc(input_path, is_background_mixed=result["is_background_mixed"])
0063 if dsc:
0064 result["requester_dsc"] = dsc
0065
0066
0067 output_file = get_str(params, "outputFile")
0068 if output_file:
0069 output_file = output_file.strip("[]'\" ")
0070 if ".edm4hep." in output_file:
0071 result["data_level"] = "simulation"
0072 elif ".edm4eic." in output_file:
0073 result["data_level"] = "reconstruction"
0074
0075
0076
0077 compact_file = get_str(params, "compactFile")
0078 if compact_file:
0079 compact_file = compact_file.strip("[]'\" ")
0080 basename = re.sub(r'\.xml$', '', compact_file.split('/')[-1])
0081 if basename.startswith("epic_"):
0082 basename = basename[len("epic_"):]
0083 result["geometry_config"] = basename
0084
0085
0086
0087
0088 if not no_beam and not include_gun:
0089 beam_match = re.search(r'_(\d+)x(\d+)(?:_(.+))?$', basename)
0090 if beam_match:
0091 result["electron_beam_energy_gev"] = int(beam_match.group(1))
0092 result["ion_beam_energy_gev"] = int(beam_match.group(2))
0093 species = beam_match.group(3)
0094 result["ion_species"] = species if species is not None else "p"
0095
0096 if include_gun:
0097
0098 particle = get_str(params, "gun.particle")
0099 if particle:
0100 result["gun_particle"] = particle
0101
0102
0103 distribution = get_str(params, "gun.distribution")
0104 if distribution:
0105 result["gun_distribution"] = distribution
0106
0107
0108
0109 energy = get_str(params, "gun.energy")
0110 mom_min = get_str(params, "gun.momentumMin")
0111 mom_max = get_str(params, "gun.momentumMax")
0112 npsim_defaults = (mom_min == "0.0" and mom_max == "10000.0")
0113
0114 if energy is not None:
0115 momentum_gev = round(float(energy) / 1000, 6)
0116 result["gun_momentum_min_gev"] = momentum_gev
0117 result["gun_momentum_max_gev"] = momentum_gev
0118 elif not npsim_defaults and mom_min is not None and mom_max is not None:
0119 result["gun_momentum_min_gev"] = round(float(mom_min) / 1000, 6)
0120 result["gun_momentum_max_gev"] = round(float(mom_max) / 1000, 6)
0121
0122
0123 theta_min = get_str(params, "gun.thetaMin")
0124 theta_max = get_str(params, "gun.thetaMax")
0125 if theta_min is not None:
0126 result["gun_theta_min_deg"] = rad_to_deg(theta_min)
0127 if theta_max is not None:
0128 result["gun_theta_max_deg"] = rad_to_deg(theta_max)
0129
0130
0131 phi_min = get_str(params, "gun.phiMin")
0132 phi_max = get_str(params, "gun.phiMax")
0133 result["gun_phi_min_deg"] = rad_to_deg(phi_min) if phi_min is not None else 0
0134 result["gun_phi_max_deg"] = rad_to_deg(phi_max) if phi_max is not None else 360
0135
0136 print(json.dumps(result))