ATLAS Offline Software
Loading...
Searching...
No Matches
Herwig7Utils.py
Go to the documentation of this file.
1# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
2
3
6
7import math, os, subprocess
8
9from AthenaCommon import Logging
10athMsgLog = Logging.logging.getLogger('Herwig7Utils')
11
12integration_grids_precision_threshold = 0.0005 # if integration xsec below a warning is issue in debug mode and an erroro in production mode
13
14
15
24
25 def __init__(self):
26 self.commands = ""
27 self.locked = False
28
29 def lock(self):
30 self.locked = True
31
32 def add(self, commands):
33 if self.locked is False:
34 self.commands += commands
35 else:
36 raise RuntimeError("The commands associated to this configuration object can't be modified anymore because the Herwig7 infile has already been written to disk. Therefore, any subsequent additional modifications can't be adopted in the Herwig7 run.")
37 return(self)
38
39 __iadd__ = add
40
41
42
47
48 def __init__(self, process_list, logger):
49 self.processes = process_list
50 self.n_initial = len(process_list)
51 self.logger = logger
52
53 def success(self):
54 result = True
55 while len(self.processes) > 0:
56 for ID, process in enumerate(self.processes):
57 returncode = process.poll()
58 if returncode is not None:
59
60
61 self.processes.remove(process)
62 if returncode == 0:
63 athMsgLog.info(ansi_format_info('Process #{} finished sucessfully, {}/{} still running'.format(process.ID, len(self.processes), self.n_initial)))
64 elif returncode > 0:
65 athMsgLog.error(ansi_format_error("Process #{} finished with error code {} (please check logfile '{}'), {}/{} still running".format(process.ID, returncode, process.logfile_title, len(self.processes), self.n_initial)))
66 result = False
67 elif returncode < 0:
68 athMsgLog.error(ansi_format_error("Process #{} was terminated by signal {} (please check logfile '{}'), {}/{} still running".format(process.ID, -returncode, process.logfile_title, len(self.processes), self.n_initial)))
69 result = False
70
71
75 athMsgLog.info("Content of integration log file '%s':", process.logfile_title)
76 athMsgLog.info("")
77 with open(process.logfile_title, 'r') as logfile:
78 for line in logfile:
79 athMsgLog.info(' %s', line.rstrip('\n'))
80 athMsgLog.info("")
81 # self.logger.info('================================================================================')
82 # self.logger.info("End of integration log file '{}'".format(process.logfile_title))
83 # self.logger.info('================================================================================')
84
85 return(result)
86
87
88
92class Process:
93
94 def __init__(self, ID, command, logfile_title):
95
96 athMsgLog.info(ansi_format_info("Starting subprocess #{} with command '{}' and logfile '{}'".format(ID, ' '.join(command), logfile_title)))
97 self.ID = ID
98 self.logfile_title = logfile_title
99 self.logfile = open(logfile_title, 'w')
100 self.process = subprocess.Popen(command, stdout=self.logfile, stderr=self.logfile)
101
102 def poll(self):
103 return(self.process.poll())
104
105
106
107def get_cross_section(run_name, integration_jobs=1):
108
109 athMsgLog.info("Calculating cross section after integration")
110 logfiles = [run_name+'.integrate'+str(integration_job)+'.log' for integration_job in range(integration_jobs)]
111
112 xsec = 0.0
113 err = 0.0
114
115 for logfile in logfiles:
116
117 athMsgLog.info("- %s", logfile)
118
119
120 with open(logfile, 'r') as log: data = log.read().strip()
121
122 with open(logfile, 'r') as log:
123
124
125 for line in log:
126 if 'Integrate ' in line:
127 n_subprocs = int(line.split('of')[1].replace(':',''))
128 athMsgLog.info(" found %s subprocesses", n_subprocs)
129 break
130
131 data = data.split("Integrate ")[1:]
132
133 for s, subproc in enumerate(data, start=1):
134 _xsec = 0.0
135 _err = 0.0
136 for line in subproc.split("\n"):
137 if 'integrated ( ' in line:
138 _xsec = float(line.split()[2])
139 _err = float(line.split()[4])
140 athMsgLog.info(" - subprocess %s: xsec = %s +/- %s nb", s, _xsec, _err)
141 xsec += _xsec
142 err += _err*_err
143
144 err = math.sqrt(err)
145
146 if err / xsec > integration_grids_precision_threshold:
147 threshold = '{}%'.format(integration_grids_precision_threshold*100.0)
148 if run_name == "Herwig_DEBUG":
149 athMsgLog.warn(ansi_format_warning('! The integration grids only have a low precision (worse than {}): xsec = {} +/- {} nb (accuracy: {:.3f}%)'.format(threshold, xsec, err, err/xsec*100.0)))
150 else:
151 athMsgLog.error(ansi_format_error('! The integration grids only have a low precision (worse than {}): xsec = {} +/- {} nb (accuracy: {:.3f}%)'.format(threshold, xsec, err, err/xsec*100.0)))
152 athMsgLog.warn(ansi_format_warning('! In order to speed up the event generation you should consider improving the statistics of the integration / phase space sampling stage (see the sampler_commands() function).'))
153 else:
154 athMsgLog.info(ansi_format_info('After integration the estimated cross section was found to be: xsec = {} +/- {} nb (accuracy: {:.3f}%)'.format(xsec, err, err/xsec*100.0)))
155
156 return(xsec, err)
157
158
159
160def get_repeated_pattern(pattern, repetitions):
161
162 return(pattern.join(['' for i in range(repetitions+1)]))
163
164
165
166def get_size(path):
167
168 size = 0
169
170 if os.path.isfile(path):
171 return(os.path.getsize(path))
172
173 elif os.path.isdir(path):
174 for dirpath, dirs, files in os.walk(path):
175 for file in files:
176 file_path = os.path.join(dirpath, file)
177 # if not os.path.islink(file_path): # exclude symlinks because MadGraph has lots of broken symlinks
178 if os.path.isfile(file_path):
179 size += os.path.getsize(file_path)
180
181 return(size)
182
183
184
185def humanize_bytes(bytes, precision=2):
186 # shamelessly stolen from
187 # http://code.activestate.com/recipes/577081-humanized-representation-of-a-number-of-bytes/
188
189 abbrevs = (
190 (1<<50, 'PiB'),
191 (1<<40, 'TiB'),
192 (1<<30, 'GiB'),
193 (1<<20, 'MiB'),
194 (1<<10, 'KiB'),
195 (1, 'byte(s)')
196 )
197 if bytes == 1:
198 return '1 byte'
199 for factor, suffix in abbrevs:
200 if bytes >= factor:
201 break
202 return '%.*f %s' % (precision, bytes / factor, suffix)
203
204
205
206def ansi_format(text, colour='None', background_colour='None',
207 bold=False, underline=False, italics=False, marked=False, strikethrough=False):
208
209 format_none = '\033[0m'
210 format_bold = '\033[1m'
211 format_underline = '\033[4m'
212 format_italics = '\033[3m'
213 format_marked = '\033[7m'
214 format_strikethrough = '\033[9m'
215
216 colours = {
217 'None': '',
218 'Black': '\033[30m',
219 'Grey': '\033[90m',
220 'Red': '\033[91m', 'DarkRed': '\033[31m',
221 'Green': '\033[92m', 'DarkGreen': '\033[32m',
222 'Yellow': '\033[93m', 'Orange': '\033[33m',
223 'Blue': '\033[94m', 'DarkBlue': '\033[34m',
224 'Pink': '\033[95m', 'DarkPink': '\033[35m',
225 'Cyan': '\033[96m', 'DarkCyan': '\033[36m',
226 'White': '\033[97m', 'LightGrey': '\033[37m',
227 }
228
229 background_colours = {
230 'None': '',
231 'Black': '\033[40m',
232 'Red': '\033[41m',
233 'Green': '\033[42m',
234 'Orange': '\033[43m',
235 'Blue': '\033[44m',
236 'Punk': '\033[45m',
237 'Cyan': '\033[46m',
238 'Grey': '\033[47m',
239 }
240
241 if colour in colours:
242 if background_colour in background_colours:
243 return (format_none
244 + colours[colour]
245 + background_colours[background_colour]
246 + (format_bold if bold else '')
247 + (format_underline if underline else '')
248 + (format_italics if italics else '')
249 + (format_marked if marked else '')
250 + (format_strikethrough if strikethrough else '')
251 + text + format_none)
252 else:
253 raise Exception("Could not find background colour '{}'.".format(background_colour))
254 else:
255 raise Exception("Could not find colour '{}'.".format(colour))
256
257
259 return (ansi_format(text, "Green"))
260
261
263 return (ansi_format(text, "Blue"))
264
265
267 return (ansi_format(text, "Yellow"))
268
269
271 return (ansi_format(text, "Red"))
272
Class for handling commands to modify the generator configuration.
Class for handling parallel local multi-processing.
__init__(self, process_list, logger)
Class for handling a single process.
__init__(self, ID, command, logfile_title)
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
ansi_format_info(text)
Blue colouring.
get_repeated_pattern(pattern, repetitions)
Return a string made up of a certain number of repetitions of the same pattern.
get_cross_section(run_name, integration_jobs=1)
Calculate the total cross section from the integration log files.
ansi_format_ok(text)
Green colouring.
ansi_format(text, colour='None', background_colour='None', bold=False, underline=False, italics=False, marked=False, strikethrough=False)
Format and colorize terminal output.
humanize_bytes(bytes, precision=2)
Convert file/folder size from bytes to units with appropriate prefixes (multiples of 1000,...
get_size(path)
Get size of file or folder.
ansi_format_warning(text)
Yellow colouring.
ansi_format_error(text)
Red colouring.