ATLAS Offline Software
Loading...
Searching...
No Matches
EventPick_tf.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3
4"""
5Transformation script to pick events from ATLAS files (RAW/BS, ESD, AOD, DAOD, EVNT, HITS) using acmd filter-files.
6"""
7
8import sys
9import re
10import logging
11from PyJobTransforms.trfExceptions import TransformExecutionException
12from PyJobTransforms.transform import transform
13from PyJobTransforms.trfExe import scriptExecutor
14import PyJobTransforms.trfArgClasses as trfArgClasses
15
16# Fetch the framework's centralized logger profile instance
17msg_log = logging.getLogger('EventPick_tf')
18
19class AcmdFilterExecutor(scriptExecutor):
20 """
21 Subclass scriptExecutor to handle dynamic ATLAS file types in the graph.
22 Parses the event file locally and passes a formatted Python list literal to acmd.
23 """
24 def __init__(self, name="AcmdFilterFiles"):
25 supported_inputs = ['BSFiles', 'ESDFiles', 'AODFiles', 'DAODFiles', 'EVNTFiles', 'HITSFiles']
26 supported_outputs = [f"{t.replace('Files', '')}_PICKED" for t in supported_inputs]
27 super().__init__(name=name, exe="acmd", inData=supported_inputs, outData=supported_outputs)
28 self.exeArgs = []
29
30 def preExecute(self, *args, **kwargs):
31 # 1. Run standard parent method execution flow
32 super().preExecute(*args, **kwargs)
33
34 # 2. Re-assign the logger directly to protect it from framework resets
35 self.log = msg_log
36
37 # 3. Identify which input and output keys were supplied on the command line
38 input_key = next((k for k in self.conf.argdict if k.startswith('input') and k.endswith('Files')), None)
39 output_key = next((k for k in self.conf.argdict if k.startswith('output') and k.endswith('File')), None)
40
41 if not input_key or not output_key:
42 raise TransformExecutionException("Execution failed: Missing required input files or output file specification.")
43
44 # 4. Extract and match data type variants
45 in_match = re.match(r"input([A-Z_]+)Files", input_key)
46 out_match = re.match(r"output([A-Z_]+)_PICKEDFile", output_key)
47
48 in_type = in_match.group(1) if in_match else None
49 out_type = out_match.group(1) if out_match else None
50
51 if in_type != out_type:
52 msg = f"Data Mismatch Error: Input type '{in_type}' does not match output type '{out_type}'! Execution aborted."
53 msg_log.critical(msg)
54 raise TransformExecutionException(msg)
55
56 # 5. Retrieve argument payloads
57 input_files = self.conf.argdict[input_key].value
58 output_file = self.conf.argdict[output_key].value[0]
59 event_list_file = self.conf.argdict['eventList'].value[0]
60
61 # 6. Read and parse the event list file into a valid Python list literal string
62 try:
63 events = []
64 with open(event_list_file, 'r') as f:
65 for line in f:
66 line = line.strip()
67 if not line or line.startswith('#'):
68 continue
69 # Handle both single event numbers or comma/space separated tokens per line
70 if ',' in line or ' ' in line:
71 # If the line contains run/event numbers like "12345, 67890", convert to tuple
72 tokens = [int(x) for x in re.split(r'[,\s]+', line) if x]
73 events.append(tuple(tokens))
74 else:
75 events.append(int(line))
76
77 # Format explicitly as a string representation of the Python list for eval() compatibility
78 selection_expr = str(events)
79 msg_log.info(f"Successfully parsed {len(events)} events from {event_list_file}")
80 except Exception as e:
81 raise TransformExecutionException(f"Failed to read/parse event list file '{event_list_file}': {str(e)}")
82
83 # 7. Construct the execution command using the evaluated string expression literal
84 self._cmd = [
85 "acmd", "filter-files",
86 "-s", selection_expr,
87 "-o", str(output_file)
88 ] + [str(f) for f in input_files]
89
90 msg_log.info(f"Graph verification passed ({in_type}Files -> {out_type}_PICKED).")
91 msg_log.info(f"Dynamically generated command: {' '.join(self._cmd)}")
92
93
94if __name__ == '__main__':
95 executor_set = set()
96 trf = transform(executor=executor_set, description='Pick specific events from multiple ATLAS formats.')
97
98 # Define parameters
99 trf.parser.add_argument('--inputBSFiles', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argBSFile, io='input', type='BS'), help='RAW/BS inputs')
100 trf.parser.add_argument('--inputAODFiles', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input', type='AOD'), help='AOD inputs')
101 trf.parser.add_argument('--inputDAODFiles', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input', type='DAOD'), help='DAOD inputs')
102 trf.parser.add_argument('--inputESDFiles', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input', type='ESD'), help='ESD inputs')
103 trf.parser.add_argument('--inputEVNTFiles', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input', type='EVNT'), help='EVNT inputs')
104 trf.parser.add_argument('--inputHITSFiles', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input', type='HITS'), help='HITS inputs')
105
106 trf.parser.add_argument('--outputBS_PICKEDFile', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argBSFile, io='output', type='BS_PICKED'), help='RAW/BS output')
107 trf.parser.add_argument('--outputAOD_PICKEDFile', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='output', type='AOD_PICKED'), help='AOD output')
108 trf.parser.add_argument('--outputDAOD_PICKEDFile', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='output', type='DAOD_PICKED'), help='DAOD output')
109 trf.parser.add_argument('--outputESD_PICKEDFile', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='output', type='ESD_PICKED'), help='ESD output')
110 trf.parser.add_argument('--outputEVNT_PICKEDFile', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='output', type='EVNT_PICKED'), help='EVNT output')
111 trf.parser.add_argument('--outputHITS_PICKEDFile', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='output', type='HITS_PICKED'), help='HITS output')
112
113 trf.parser.add_argument('--eventList', nargs=1, type=trfArgClasses.argFactory(trfArgClasses.argFile, io='input'), required=True, help='Event List text file')
114
115 acmd_executor = AcmdFilterExecutor()
116 trf.appendToExecutorSet(acmd_executor)
117
118 trf.parseCmdLineArgs(sys.argv[1:])
119 trf.execute()
120 trf.generateReport()
121 sys.exit(trf.exitCode)
preExecute(self, *args, **kwargs)
__init__(self, name="AcmdFilterFiles")
STL class.
Main package for new style ATLAS job transforms.
Transform argument class definitions.
Transform execution functions.