ATLAS Offline Software
CPBaseRunner.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2 
3 import argparse
4 from AnaAlgorithm.Logging import logging
5 from abc import ABC, abstractmethod
6 import os
7 
8 class CPBaseRunner(ABC):
9  def __init__(self):
10  self.logger = logging.getLogger("CPBaseRunner")
11  self._args = None
12  self._inputList = None
14  # parse the arguments here is a bad idea
15 
16  @property
17  def args(self):
18  if self._args is None:
19  self._args = self.parser.parse_args()
20  return self._args
21 
22  @property
23  def inputList(self):
24  if self._inputList is None:
25  if self.args.input_list.endswith('.txt'):
26  self._inputList = CPBaseRunner._parseInputFileList(self.args.input_list)
27  elif ".root" in self.args.input_list:
28  self._inputList = [self.args.input_list]
29  else:
30  raise FileNotFoundError(f'Input file list \"{self.args.input_list}\" is not supported!'
31  'Please provide a text file with a list of input files or a single root file.')
32  self.logger.info("Initialized input files: %s", self._inputList)
33  return self._inputList
34 
35  @property
36  def outputName(self):
37  if self.args.output_name.endswith('.root'):
38  return self.args.output_name[:-5]
39  else:
40  return self.args.output_name
41 
42  def printFlags(self):
43  self.logger.info("="*73)
44  self.logger.info("="*20 + "FLAG CONFIGURATION" + "="*20)
45  self.logger.info("="*73)
46  self.logger.info(" Input files: %s", self.flags.Input.isMC)
47  self.logger.info(" RunNumber: %s", self.flags.Input.RunNumbers)
48  self.logger.info(" MCCampaign: %s", self.flags.Input.MCCampaign)
49  self.logger.info(" GeneratorInfo: %s", self.flags.Input.GeneratorsInfo)
50  self.logger.info(" MaxEvents: %s", self.flags.Exec.MaxEvents)
51  self.logger.info(" SkipEvents: %s", self.flags.Exec.SkipEvents)
52  self.logger.info("="*73)
53 
54  @abstractmethod
55  def addCustomArguments(self):
56  pass
57 
58  @abstractmethod
59  def makeAlgSequence(self):
60  pass
61 
62  @abstractmethod
63  def run(self):
64  pass
65 
66  # The responsiblity of flag.lock will pass to the caller
68  from AthenaConfiguration.AllConfigFlags import initConfigFlags
69  flags = initConfigFlags()
70  flags.Input.Files = self.inputList
71  flags.Exec.MaxEvents = self.args.max_events
72  flags.Exec.SkipEvents = self.args.skip_n_events
73  return flags
74 
76  parser = argparse.ArgumentParser(
77  description='Runscript for CP Algorithm unit tests')
78  baseGroup = parser.add_argument_group('Base Script Options')
79  baseGroup.add_argument('-i', '--input-list', dest='input_list',
80  help='path to text file containing list of input files, or a single root file')
81  baseGroup.add_argument('-o','--output-name', dest='output_name', default='output',
82  help='output name of the analysis root file')
83  baseGroup.add_argument('-e', '--max-events', dest='max_events', type=int, default=-1,
84  help='Number of events to run')
85  baseGroup.add_argument('-t', '--text-config', dest='text_config',
86  help='path to the YAML configuration file. Tips: use atlas_install_data(path/to/*.yaml) in CMakeLists.txt can help locating the config just by the config file name.')
87  baseGroup.add_argument('--no-systematics', dest='no_systematics',
88  action='store_true', help='Disable systematics')
89  baseGroup.add_argument('--skip-n-events', dest='skip_n_events', type=int, default=0,
90  help='Skip the first N events in the run, not first N events for each file. This is meant for debugging only. \nIn Eventloop, this option disable the cutbookkeeper algorithms due to technical reasons, and can only be ran in direct-driver.')
91  return parser
92 
93  def _readYamlConfig(self):
94  from AthenaCommon.Utils.unixtools import find_datafile
95  yamlconfig = find_datafile(self.args.text_config)
96  if not yamlconfig:
97  raise FileNotFoundError(f'Failed to locate \"{self.args.text_config}\" config file!'
98  'Check if you have a typo in -t/--text-config argument or missing file in the analysis configuration sub-directory.')
99  self.logger.info("Setting up configuration based on YAML config:")
100  from AnalysisAlgorithmsConfig.ConfigText import TextConfig
101  config = TextConfig(yamlconfig)
102  return config
103 
105  files = []
106  with open(path, 'r') as inputText:
107  for line in inputText.readlines():
108  # Strip the line and skip comments and empty lines
109  line = line.strip()
110  if line.startswith('#') or not line:
111  continue
112  if os.path.isdir(line):
113  if not os.listdir(line):
114  raise FileNotFoundError(f"The directory \"{path}\" is empty. Please provide a directory with .root files.")
115  for root_file in os.listdir(line):
116  if '.root' in root_file:
117  files.append(os.path.join(line, root_file))
118  else:
119  files += line.split(',')
120  # Remove leading/trailing whitespaces from file names
121  files = [file.strip() for file in files]
122  return files
123 
124  def setup(self):
125  self.parser.parse_args()
126  self.config = self._readYamlConfig()
128 
130  self.parser.description = 'CPRunScript available arguments'
131  self.parser.usage = argparse.SUPPRESS
132  self.parser.print_help()
python.CPBaseRunner.CPBaseRunner._parseInputFileList
def _parseInputFileList(path)
Definition: CPBaseRunner.py:104
python.CPBaseRunner.CPBaseRunner.parser
parser
Definition: CPBaseRunner.py:13
python.CPBaseRunner.CPBaseRunner._readYamlConfig
def _readYamlConfig(self)
Definition: CPBaseRunner.py:93
python.CPBaseRunner.CPBaseRunner._defaultFlagsInitialization
def _defaultFlagsInitialization(self)
Definition: CPBaseRunner.py:67
python.CPBaseRunner.CPBaseRunner.addCustomArguments
def addCustomArguments(self)
Definition: CPBaseRunner.py:55
python.CPBaseRunner.CPBaseRunner.printFlags
def printFlags(self)
Definition: CPBaseRunner.py:42
python.CPBaseRunner.CPBaseRunner._defaultParseArguments
def _defaultParseArguments(self)
Definition: CPBaseRunner.py:75
python.CPBaseRunner.CPBaseRunner.outputName
def outputName(self)
Definition: CPBaseRunner.py:36
python.CPBaseRunner.CPBaseRunner.printAvailableArguments
def printAvailableArguments(self)
Definition: CPBaseRunner.py:129
python.CPBaseRunner.CPBaseRunner.run
def run(self)
Definition: CPBaseRunner.py:63
python.CPBaseRunner.CPBaseRunner.makeAlgSequence
def makeAlgSequence(self)
Definition: CPBaseRunner.py:59
python.CPBaseRunner.CPBaseRunner.setup
def setup(self)
Definition: CPBaseRunner.py:124
python.CPBaseRunner.CPBaseRunner
Definition: CPBaseRunner.py:8
python.CPBaseRunner.CPBaseRunner.flags
flags
Definition: CPBaseRunner.py:127
Trk::open
@ open
Definition: BinningType.h:40
python.CPBaseRunner.CPBaseRunner.config
config
Definition: CPBaseRunner.py:126
python.CPBaseRunner.CPBaseRunner.args
def args(self)
Definition: CPBaseRunner.py:17
python.AllConfigFlags.initConfigFlags
def initConfigFlags()
Definition: AllConfigFlags.py:19
confTool.parse_args
def parse_args()
Definition: confTool.py:36
python.CPBaseRunner.CPBaseRunner.logger
logger
Definition: CPBaseRunner.py:10
python.CPBaseRunner.CPBaseRunner._inputList
_inputList
Definition: CPBaseRunner.py:12
python.CPBaseRunner.CPBaseRunner.inputList
def inputList(self)
Definition: CPBaseRunner.py:23
python.Utils.unixtools.find_datafile
def find_datafile(fname, pathlist=None, access=os.R_OK)
pathresolver-like helper function --------------------------------------—
Definition: unixtools.py:67
python.CPBaseRunner.CPBaseRunner._args
_args
Definition: CPBaseRunner.py:11
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
python.CPBaseRunner.CPBaseRunner.__init__
def __init__(self)
Definition: CPBaseRunner.py:9