ATLAS Offline Software
Loading...
Searching...
No Matches
ProphecyPowhegMerge.py
Go to the documentation of this file.
1# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2
3import os, subprocess, time, tarfile
4from AthenaCommon import Logging
5from PowhegControl.utility import HeartbeatTimer
6
7
11
12 __run_directory = os.environ['PATH']
13
14
15 __logger = Logging.logging.getLogger('ProphecyPowhegMerger')
16
17
18 _merger_executable = 'mergeProphecy4f.exe'
19
20 def __init__( self, runArgs=None, opts=None ) :
21
22
23 self.__output_events_file_name = 'ProphecyPowhegMergedOTF._1.events'
24
25
26
27 self.__input_powheg_file_name = 'PowhegOTF._1.events'
28 self.__input_prophecy4e_file_name = 'ProphecyOTF4e._1.events'
29 self.__input_prophecy4mu_file_name = 'ProphecyOTF4mu._1.events'
30 self.__input_prophecy2e2mu_file_name = 'ProphecyOTF2e2mu._1.events'
32
33
34 if runArgs is None :
35 self.logger.warning( 'No run arguments found! Using defaults.' )
36 else :
37 # Read values from runArgs
38 # Set inputGeneratorFile to match output events file. Otherwise Generate_trf check will fail.
39 runArgs.inputGeneratorFile = self.output_events_file_name
40
41
42 def merge(self) :
43
44 self.logger.info( 'Starting ProphecyPowhegMerger merge' )
45
46 powhegLHE = self.input_powheg_file_name
47 prophecyLHE4e = self.input_prophecy4e_file_name
48 prophecyLHE4mu = self.input_prophecy4mu_file_name
49 prophecyLHE2e2mu = self.input_prophecy2e2mu_file_name
50 random_seed = str(self.random_seed)
51
52 myinputfiles = powhegLHE
53 genInputFiles = myinputfiles.split(',')
54 numberOfFiles = len(genInputFiles)
55 # if there is a single file, make a symlink. If multiple files, merge them into one output eventsFile
56 if numberOfFiles > 0:
57 allFiles = []
58 for file in genInputFiles:
59 file_1 = file
60 # untar as needed
61 if tarfile.is_tarfile(file):
62 tar = tarfile.open(file)
63 tar.extractall()
64 tar.close()
65 file_1 = file.replace("tar.gz.1","events")
66 self.logger.info( 'Extracted tar file, and renaming {0} to {1}'.format ( file, file_1 ) )
67 pass
68
69 # The only input format where merging is permitted is LHE
70 with open(file_1, 'r') as f:
71 first_line = f.readline()
72 self.logger.info( 'first_line {0}'.format ( first_line ) )
73 if(not ("LesHouche" in first_line)):
74 raise RuntimeError("%s is NOT a LesHouche file" % file)
75 allFiles.append(file_1)
76 powhegLHE_input = "merged_powheg_events.lhe"
77 self.merge_lhe_files(allFiles, powhegLHE_input)
78
79
80 time_start = time.time()
81 self.logger.info( 'Input files: {0} {1} {2} {3}'.format( powhegLHE_input, prophecyLHE4e, prophecyLHE4mu, prophecyLHE2e2mu ) )
82
83
84 heartbeat = HeartbeatTimer(600., "{}/eventLoopHeartBeat.txt".format(self.__run_directory))
85 heartbeat.setName("heartbeat thread")
86 heartbeat.daemon = True # Allow program to exit if this is the only live thread
87 heartbeat.start()
88
89
90 self.logger.info( 'Checking if {0} exists.'.format( powhegLHE_input ) )
91 if not os.path.isfile( powhegLHE_input ):
92 self.logger.error( 'File {0} does NOT exist.'.format( powhegLHE_input ) )
93 raise ValueError('File {0} does NOT exist.'.format( powhegLHE_input ))
94
95 self.logger.info( 'Checking if {0} exists.'.format( prophecyLHE4e ) )
96 if not os.path.isfile( prophecyLHE4e ):
97 self.logger.error( 'File {0} does NOT exist.'.format( prophecyLHE4e ) )
98 raise ValueError('File {0} does NOT exist.'.format( prophecyLHE4e ))
99
100 self.logger.info( 'Checking if {0} exists.'.format( prophecyLHE4mu ) )
101 if not os.path.isfile( prophecyLHE4mu ):
102 self.logger.error( 'File {0} does NOT exist.'.format( prophecyLHE4mu ) )
103 raise ValueError('File {0} does NOT exist.'.format( prophecyLHE4mu ))
104
105 self.logger.info( 'Checking if {0} exists.'.format( prophecyLHE2e2mu ) )
106 if not os.path.isfile( prophecyLHE2e2mu ):
107 self.logger.error( 'File {0} does NOT exist.'.format( prophecyLHE2e2mu ) )
108 raise ValueError('File {0} does NOT exist.'.format( prophecyLHE2e2mu ))
109
110 self.logger.info( 'Input files found. Moving them to temporary files to produce properly named final output {0}.'.format( self.output_events_file_name ) )
111
112 try :
113 os.rename( prophecyLHE4e, prophecyLHE4e + '.tmp' )
114 except OSError :
115 self.logger.error( 'Moving of file {0} failed - not expected.'.format( prophecyLHE4e ) )
116
117 try :
118 os.rename( prophecyLHE4mu, prophecyLHE4mu + '.tmp' )
119 except OSError :
120 self.logger.error( 'Moving of file {0} failed - not expected.'.format( prophecyLHE4mu ) )
121
122 try :
123 os.rename( prophecyLHE2e2mu, prophecyLHE2e2mu + '.tmp' )
124 except OSError :
125 self.logger.error( 'Moving of file {0} failed - not expected.'.format( prophecyLHE2e2mu ) )
126
128
129 self.runMerging(powhegLHE_input, prophecyLHE4e + '.tmp', prophecyLHE4mu + '.tmp', prophecyLHE2e2mu + '.tmp', random_seed)
130
131 heartbeat.cancel()
132
133
134 generation_end = time.time()
135 elapsed_time = generation_end - time_start
136 self.logger.info( 'Running ProphecyPowhegMerger took {0}.'.format( HeartbeatTimer.readable_duration(elapsed_time) ) )
137
138 self.logger.info( 'Removing initial LHE files of Prophecy and Powheg stored as *tmp.' )
139
140
141 self.logger.info( 'Finished at {0}'.format( time.asctime() ) )
142 return
143
144
145 def runMerging(configurator, powhegLHE, prophecyLHE4e, prophecyLHE4mu, prophecyLHE2e2mu, random_seed, stdin=None) :
146 configurator.logger.info( 'runMerging on {0}, {1}, {2} and {3}'.format( powhegLHE, prophecyLHE4e, prophecyLHE4mu, prophecyLHE2e2mu ) )
147 if configurator.logger.level >= Logging.logging.DEBUG :
148 configurator.running_process.append(subprocess.Popen( [configurator._merger_executable,'--inPowheg',powhegLHE,'--inProphecy4e',prophecyLHE4e,'--inProphecy4mu',prophecyLHE4mu,'--inProphecy2e2mu',prophecyLHE2e2mu,'--outLHE',configurator.output_events_file_name,'--randomSeed',random_seed,'--debug'], stdout=subprocess.PIPE, stdin=stdin, stderr=subprocess.STDOUT ) )
149 else :
150 configurator.running_process.append(subprocess.Popen( [configurator._merger_executable,'--inPowheg',powhegLHE,'--inProphecy4e',prophecyLHE4e,'--inProphecy4mu',prophecyLHE4mu,'--inProphecy2e2mu',prophecyLHE2e2mu,'--outLHE',configurator.output_events_file_name,'--randomSeed',random_seed,'--debug'], stdout=subprocess.PIPE, stdin=stdin, stderr=subprocess.STDOUT ) )
151 configurator.logger.info( 'runMerging run mergeProphecy4f: --inPowheg {0} --inProphecy4e {1} --inProphecy4mu {2} --inProphecy2e2mu {3} --outLHE {4} --randomSeed {5}'.format( powhegLHE, prophecyLHE4e, prophecyLHE4mu, prophecyLHE2e2mu, configurator.output_events_file_name,random_seed) )
152
153 while configurator.running_process :
154 # Write output buffer if any
155 for process in configurator.running_process :
156 while True :
157 output = process.stdout.readline().rstrip()
158 if len(output) == 0 : break
159 configurator.logger.info( '{0}'.format(output) )
160 if process.poll() is not None : # process has ended
161 # Flush buffer and print final output (if any) to screen
162 process.stdout.flush()
163 while True :
164 output = process.stdout.readline().rstrip()
165 if len(output) == 0 : break
166 configurator.logger.info( '{0}'.format(output) )
167 # Close output stream and remove process from list
168 process.stdout.close()
169 configurator.running_process.remove( process )
170 configurator.logger.info( 'Merging finished - all done.' )
171
172
173 @property
175 return self.__output_events_file_name
176
177
178 @property
180 return self.__input_powheg_file_name
181
182
183 @input_powheg_file_name.setter
184 def input_powheg_file_name(self, value) :
185 self.__input_powheg_file_name = value
186
187
188 @property
192
193 @property
197 @property
201 @property
202 def random_seed(self) :
203 return self.__random_seed
204
205
206 @input_prophecy4e_file_name.setter
207 def input_prophecy4e_file_name(self, value) :
209
210
211 @input_prophecy4mu_file_name.setter
214
215 @input_prophecy2e2mu_file_name.setter
218
219 @random_seed.setter
220 def random_seed(self, value) :
221 self.__random_seed = value
222
223
224 @property
225 def logger(self) :
226 return self.__logger
227
228 # This function merges a list of input LHE file to make one outputFile. The header is taken from the first
229 # file, but the number of events is updated to equal the total number of events in all the input files
230 def merge_lhe_files(self, listOfFiles, outputFile):
231 if(os.path.exists(outputFile)):
232 self.logger.info( 'outputFile {0} already exists. Will rename to {1}.OLD'.format ( outputFile, outputFile ) )
233 os.rename(outputFile,outputFile+".OLD")
234 output = open(outputFile,'w')
235 holdHeader = ""
236 nevents=0
237 for file in listOfFiles:
238 cmd = "grep /event "+file+" | wc -l"
239 nevents+=int(subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True))
240
241 for file in listOfFiles:
242 inHeader = True
243 header = ""
244 self.logger.info( '*** Starting to merge file {0}'.format ( file ) )
245 for line in open(file,"r"):
246
251 if("<event" in line and inHeader):
252 inHeader = False
253 if(len(holdHeader)<1):
254 holdHeader = header
255 output.write(header)
256 output.write(line)
257
259 elif(not inHeader and not ("</LesHouchesEvents>" in line)):
260 output.write(line)
261 if(inHeader):
262
263 if("nevents" in line):
264
265 tmp = line.split("=")
266 line = line.replace(tmp[0],str(nevents))
267 elif("numevts" in line):
268
269 tmp = line.split(" ")
270 nnn = str(nevents)
271 line = line.replace(tmp[1],nnn)
272 header+=line
273 output.write("</LesHouchesEvents>\n")
274 output.close()
275
if(febId1==febId2)
Base class for configurable objects in the jobOptions.
runMerging(configurator, powhegLHE, prophecyLHE4e, prophecyLHE4mu, prophecyLHE2e2mu, random_seed, stdin=None)
__run_directory
Set up run directory and path to Prophecy.
str __input_powheg_file_name
Using default output names from PowhegConfig_base and ProphecyConfig.
input_powheg_file_name(self)
Get input Powheg file name.
str __output_events_file_name
This needs to be set so that Generate_trf finds an appropriate file format for showering.
input_prophecy4mu_file_name(self)
Get input Prophecy file name.
input_prophecy4e_file_name(self)
Get input Prophecy file name.
Definition merge.py:1