ATLAS Offline Software
Loading...
Searching...
No Matches
python.EventLoopCPRunScript.EventLoopCPRunScript Class Reference
Inheritance diagram for python.EventLoopCPRunScript.EventLoopCPRunScript:
Collaboration diagram for python.EventLoopCPRunScript.EventLoopCPRunScript:

Public Member Functions

 __init__ (self)
 addCustomArguments (self)
 makeAlgSequence (self)
 readSamples (self)
 moveOutputFiles (self)
 driverSubmit (self, driver)
 getExitCode (self)
 run (self)

Public Attributes

 algSeq = None
 sampleHandler = ROOT.SH.SampleHandler()
 inputList
 job

Protected Member Functions

 _dumpFullConfig (self)

Detailed Description

Definition at line 6 of file EventLoopCPRunScript.py.

Constructor & Destructor Documentation

◆ __init__()

python.EventLoopCPRunScript.EventLoopCPRunScript.__init__ ( self)

Definition at line 7 of file EventLoopCPRunScript.py.

7 def __init__(self):
8 super().__init__()
9 self.logger.info("EventLoopCPRunScript initialized")
10 self.addCustomArguments()
11 self.algSeq = None
12 # Avoid putting call to parse_args() here! Otherwise it is hard to retrieve the parser infos
13

Member Function Documentation

◆ _dumpFullConfig()

python.EventLoopCPRunScript.EventLoopCPRunScript._dumpFullConfig ( self)
protected

Definition at line 56 of file EventLoopCPRunScript.py.

56 def _dumpFullConfig(self):
57 from AnalysisAlgorithmsConfig.SaveConfigUtils import save_algs_from_sequence_ELjob, combine_tools_and_algorithms_ELjob
58 import json
59 with(open("_alg_sequence.json", 'w', encoding='utf-8')) as seq_out_file:
60 output_dict = {}
61 try:
62 save_algs_from_sequence_ELjob(self.algSeq, output_dict)
63 json.dump(output_dict, seq_out_file, ensure_ascii=False, indent=4)
64 except Exception as e:
65 self.logger.warning(f'Dumping full config failed with: {e}')
66 self.logger.warning('Please also check if "PrintConfiguration" is enabled in the text config.')
67 try:
68 combine_tools_and_algorithms_ELjob(combine_dictionaries=True, alg_file="_alg_sequence.json", output_file="full_config.json")
69 self.logger.info("Combining full config to full_config.json succeeded")
70
71 except Exception as e:
72 self.logger.warning(f'Combining full config failed with: {e}')
73 self.logger.warning('Please also check if "PrintConfiguration" is enabled in the text config.')
74 finally:
75 os.remove("_alg_sequence.json")
76

◆ addCustomArguments()

python.EventLoopCPRunScript.EventLoopCPRunScript.addCustomArguments ( self)

Definition at line 14 of file EventLoopCPRunScript.py.

14 def addCustomArguments(self):
15 # add arguments here
16 derivedGroup = self.parser.add_argument_group('EventLoop specific arguments')
17 derivedGroup.add_argument('--direct-driver', dest='direct_driver',
18 action='store_true', help='Run the job with the direct driver')
19 derivedGroup.add_argument('--work-dir', dest='work_dir', nargs='?', const='workDir', default=None,
20 help='The work directory for the EL job. defaults to "workDir".')
21 derivedGroup.add_argument('--dump-full-config', dest='dump_full_config', action='store_true', help='Save the full CP configuration log to a json file. This can be useful for debugging purposes.')
22
23 expertGroup = self.parser.add_argument_group('Experts arguments')
24 expertGroup.add_argument('--run-perf-stat', dest='run_perf_stat', action='store_true', help='Run xAOD::PerfStats to get input branch access data. This is mostly useful for AMG experts wanting to understand branch access patterns.')
25 expertGroup.add_argument('--algorithm-timers', dest='algorithm_timers', action='store_true', help='Enable algorithm timers. This is mostly useful for AMG experts wanting to understand tool performance.')
26 expertGroup.add_argument('--algorithm-memory-monitoring', dest='algorithm_memory_monitoring', action='store_true', help='Enable algorithm memory monitoring. This is mostly useful for AMG experts wanting to understand tool memory usage. Note that this is imperfect and may in cases assign memory to the wrong algorithm.')
27 return
28

◆ driverSubmit()

python.EventLoopCPRunScript.EventLoopCPRunScript.driverSubmit ( self,
driver )
Important if you want to run code after submitting the job, with external driver e.g., ExecDriver.
Assistant function to call driver submit. Move the submission to a child process to avoid the main process being terminated.
Directly calling external driver submission will not return controls to the main process, the main thread will be terminated.

Definition at line 110 of file EventLoopCPRunScript.py.

110 def driverSubmit(self, driver):
111 '''
112 Important if you want to run code after submitting the job, with external driver e.g., ExecDriver.
113 Assistant function to call driver submit. Move the submission to a child process to avoid the main process being terminated.
114 Directly calling external driver submission will not return controls to the main process, the main thread will be terminated.
115 '''
116 if (pid := os.fork()) == 0: # child process
117 try:
118 name = self.args.work_dir if self.args.work_dir else 'workDir'
119 driver.submit(self.job, name)
120 except Exception:
121 import traceback
122 traceback.print_exc()
123 sys.stdout.flush()
124 sys.stderr.flush()
125 os._exit(1)
126 sys.stdout.flush()
127 sys.stderr.flush()
128 os._exit(0)
129 else:
130 _, status = os.waitpid(pid, 0) # parent waits for child process to finish
131 if os.waitstatus_to_exitcode(status) != 0:
132 self.logger.error(f'Job submission in child process failed with exit code {os.waitstatus_to_exitcode(status)}')
133 return
134

◆ getExitCode()

python.EventLoopCPRunScript.EventLoopCPRunScript.getExitCode ( self)

Definition at line 135 of file EventLoopCPRunScript.py.

135 def getExitCode(self):
136 import ROOT
137 statusCode = ROOT.EL.Driver.retrieve(self.args.work_dir if self.args.work_dir else 'workDir')
138 if statusCode:
139 return 0
140 return 1
141

◆ makeAlgSequence()

python.EventLoopCPRunScript.EventLoopCPRunScript.makeAlgSequence ( self)

Definition at line 29 of file EventLoopCPRunScript.py.

29 def makeAlgSequence(self):
30 from AnaAlgorithm.AlgSequence import AlgSequence
31 from AnalysisAlgorithmsConfig.ConfigAccumulator import ConfigAccumulator
32 algSeq = AlgSequence()
33 self.logger.info("Configuring algorithms based on YAML file")
34 configSeq = self.config.configure()
35 self.logger.info("Configuring common services")
36 configAccumulator = ConfigAccumulator(flags=self.flags,
37 algSeq=algSeq,
38 noSystematics=self.args.no_systematics)
39 self.logger.info("Configuring algorithms")
40 configSeq.fullConfigure(configAccumulator)
41 self.algSeq = algSeq
42 self.modifyAlgSequence()
43 return algSeq
44
bool configure(asg::AnaToolHandle< ITrigGlobalEfficiencyCorrectionTool > &tool, ToolHandleArray< IAsgElectronEfficiencyCorrectionTool > &electronEffToolsHandles, ToolHandleArray< IAsgElectronEfficiencyCorrectionTool > &electronSFToolsHandles, ToolHandleArray< CP::IMuonTriggerScaleFactors > &muonToolsHandles, ToolHandleArray< IAsgPhotonEfficiencyCorrectionTool > &photonEffToolsHandles, ToolHandleArray< IAsgPhotonEfficiencyCorrectionTool > &photonSFToolsHandles, const std::string &triggers, const std::map< std::string, std::string > &legsPerTool, unsigned long nToys, bool debug)

◆ moveOutputFiles()

python.EventLoopCPRunScript.EventLoopCPRunScript.moveOutputFiles ( self)

Definition at line 77 of file EventLoopCPRunScript.py.

77 def moveOutputFiles(self):
78 from pathlib import Path
79 import shutil
80 self.logger.info("Moving the analysis root file and the hist file to the top level.")
81 workDir = Path(self.args.work_dir) if self.args.work_dir else Path('workDir')
82 rootfileSymlink = (workDir / 'data-ANALYSIS' / f'{self.outputName}.root')
83 rootfilePath = rootfileSymlink.resolve()
84 histfileSymlink = (workDir / f'hist-{self.outputName}.root')
85 histfilePath = histfileSymlink.resolve()
86 currentDir = Path.cwd()
87 # move ntuple file if it exists
88 if rootfilePath.exists():
89 self.logger.info(f"Moving {rootfilePath} to {currentDir / f'{self.outputName}.root'}")
90 if rootfileSymlink.is_symlink(): # The check is needed to avoid FileNotFoundError if using direct driver
91 rootfileSymlink.unlink()
92 shutil.move(str(rootfilePath), str(currentDir / f"{self.outputName}.root"))
93 else:
94 self.logger.warning(f"Root file {rootfilePath} does not exist or merging is enabled, skipping move.")
95 #move histogram file if it exists
96 if histfilePath.exists():
97 self.logger.info(f"Moving {histfilePath} to {currentDir / f'hist-{self.outputName}.root'}")
98 if histfileSymlink.is_symlink(): # The check is needed to avoid FileNotFoundError if using direct driver
99 histfileSymlink.unlink()
100 shutil.move(str(histfilePath), str(currentDir / f"hist-{self.outputName}.root"))
101 else:
102 self.logger.warning(f"Histogram file {histfilePath} does not exist or merging, skipping move.")
103
104 newHistFile = currentDir / f"hist-{self.outputName}.root"
105 # rename merged hist-ntuple to output_name.root
106 if self.args.merge_output_files and newHistFile.exists():
107 self.logger.info(f"renaming the hist-{self.outputName}.root to {self.outputName}.root")
108 newHistFile.rename(currentDir / f"{self.outputName}.root")
109

◆ readSamples()

python.EventLoopCPRunScript.EventLoopCPRunScript.readSamples ( self)

Definition at line 45 of file EventLoopCPRunScript.py.

45 def readSamples(self):
46 import ROOT
47 self.sampleHandler = ROOT.SH.SampleHandler()
48 sampleFiles = ROOT.SH.SampleLocal(f"{self.outputName}")
49 self.logger.info("Adding files to the sample handler")
50 for file in self.inputList:
51 sampleFiles.add(file)
52 self.sampleHandler.add(sampleFiles)
53
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55

◆ run()

python.EventLoopCPRunScript.EventLoopCPRunScript.run ( self)

Definition at line 142 of file EventLoopCPRunScript.py.

142 def run(self):
143 self.setup()
144 # importing ROOT has a long upfront time, so we do it here
145 import ROOT
146 ROOT.xAOD.Init().ignore()
147 self.readSamples()
148 self.flags.lock()
149 self.printFlags()
150
151 self.job = ROOT.EL.Job()
152 self.job.sampleHandler(self.sampleHandler)
153 self.job.options().setDouble(ROOT.EL.Job.optFilesPerWorker, 100)
154 self.job.options().setDouble(ROOT.EL.Job.optMaxEvents, self.flags.Exec.MaxEvents)
155 self.job.options().setString(ROOT.EL.Job.optSubmitDirMode, 'unique-link')
156 self.job.options().setDouble(ROOT.EL.Job.optSkipEvents, self.flags.Exec.SkipEvents)
157
158 for alg in self.makeAlgSequence():
159 self.job.algsAdd(alg)
160 if self.args.merge_output_files:
161 self.job.options().setString(ROOT.EL.Job.optStreamAliases, "ANALYSIS=" + ROOT.EL.Job.histogramStreamName)
162 else:
163 self.job.outputAdd(ROOT.EL.OutputStream('ANALYSIS'))
164
165 if self.args.run_perf_stat:
166 self.job.options().setBool(ROOT.EL.Job.optXAODPerfStats, 1)
167 if self.args.algorithm_timers:
168 self.job.options().setBool(ROOT.EL.Job.optAlgorithmTimer, 1)
169 if self.args.algorithm_memory_monitoring:
170 self.job.options().setBool(ROOT.EL.Job.optAlgorithmMemoryMonitor, 1)
171
172 driver = ROOT.EL.DirectDriver() if self.args.direct_driver else ROOT.EL.ExecDriver()
173 self.driverSubmit(driver)
174
175 if self.args.dump_full_config:
176 self._dumpFullConfig()
177 exitCode = self.getExitCode()
178
179 if self.args.work_dir is None: # move output if work_dir is not used
180 self.moveOutputFiles()
181
182 sys.exit(exitCode)
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
int run(int argc, char *argv[])

Member Data Documentation

◆ algSeq

python.EventLoopCPRunScript.EventLoopCPRunScript.algSeq = None

Definition at line 11 of file EventLoopCPRunScript.py.

◆ inputList

python.EventLoopCPRunScript.EventLoopCPRunScript.inputList

Definition at line 50 of file EventLoopCPRunScript.py.

◆ job

python.EventLoopCPRunScript.EventLoopCPRunScript.job

Definition at line 119 of file EventLoopCPRunScript.py.

◆ sampleHandler

python.EventLoopCPRunScript.EventLoopCPRunScript.sampleHandler = ROOT.SH.SampleHandler()

Definition at line 47 of file EventLoopCPRunScript.py.


The documentation for this class was generated from the following file: