ATLAS Offline Software
ProphecyPowhegMerge.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 import os, subprocess, time, tarfile
4 from AthenaCommon import Logging
5 from 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'
31  self.__random_seed = 0
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 
127  self.running_process = []
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
190  return self.__input_prophecy4e_file_name
191 
192 
193  @property
196 
197  @property
200 
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) :
208  self.__input_prophecy4e_file_name = value
209 
210 
211  @input_prophecy4mu_file_name.setter
212  def input_prophecy4mu_file_name(self, value) :
213  self.__input_prophecy4mu_file_name = value
214 
215  @input_prophecy2e2mu_file_name.setter
216  def input_prophecy2e2mu_file_name(self, value) :
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 
grepfile.info
info
Definition: grepfile.py:38
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__run_directory
__run_directory
Set up run directory and path to Prophecy.
Definition: ProphecyPowhegMerge.py:12
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__random_seed
__random_seed
Definition: ProphecyPowhegMerge.py:31
python.ProphecyPowhegMerge.ProphecyPowhegMerge.merge
def merge(self)
Initialise runcard with generic options.
Definition: ProphecyPowhegMerge.py:42
vtune_athena.format
format
Definition: vtune_athena.py:14
python.ProphecyPowhegMerge.ProphecyPowhegMerge.output_events_file_name
def output_events_file_name(self)
Get output file name.
Definition: ProphecyPowhegMerge.py:174
python.ProphecyPowhegMerge.ProphecyPowhegMerge.input_powheg_file_name
def input_powheg_file_name(self)
Get input Powheg file name.
Definition: ProphecyPowhegMerge.py:179
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__init__
def __init__(self, runArgs=None, opts=None)
Definition: ProphecyPowhegMerge.py:20
python.ProphecyPowhegMerge.ProphecyPowhegMerge.input_prophecy4e_file_name
def input_prophecy4e_file_name(self)
Get input Prophecy file name.
Definition: ProphecyPowhegMerge.py:189
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__output_events_file_name
__output_events_file_name
This needs to be set so that Generate_trf finds an appropriate file format for showering.
Definition: ProphecyPowhegMerge.py:23
python.ProphecyPowhegMerge.ProphecyPowhegMerge.runMerging
def runMerging(configurator, powhegLHE, prophecyLHE4e, prophecyLHE4mu, prophecyLHE2e2mu, random_seed, stdin=None)
Definition: ProphecyPowhegMerge.py:145
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__input_powheg_file_name
__input_powheg_file_name
Using default output names from PowhegConfig_base and ProphecyConfig.
Definition: ProphecyPowhegMerge.py:27
python.ProphecyPowhegMerge.ProphecyPowhegMerge.input_prophecy4mu_file_name
def input_prophecy4mu_file_name(self)
Get input Prophecy file name.
Definition: ProphecyPowhegMerge.py:194
python.ProphecyPowhegMerge.ProphecyPowhegMerge.running_process
running_process
Initialise timer.
Definition: ProphecyPowhegMerge.py:127
python.ProphecyPowhegMerge.ProphecyPowhegMerge.random_seed
def random_seed(self)
Definition: ProphecyPowhegMerge.py:202
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__input_prophecy2e2mu_file_name
__input_prophecy2e2mu_file_name
Definition: ProphecyPowhegMerge.py:30
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__input_prophecy4e_file_name
__input_prophecy4e_file_name
Definition: ProphecyPowhegMerge.py:28
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__logger
__logger
Setup athena-compatible logger.
Definition: ProphecyPowhegMerge.py:15
python.ProphecyPowhegMerge.ProphecyPowhegMerge.input_prophecy2e2mu_file_name
def input_prophecy2e2mu_file_name(self)
Definition: ProphecyPowhegMerge.py:198
Trk::open
@ open
Definition: BinningType.h:40
python.ProphecyPowhegMerge.ProphecyPowhegMerge
Base class for configurable objects in the jobOptions.
Definition: ProphecyPowhegMerge.py:10
python.ProphecyPowhegMerge.ProphecyPowhegMerge.logger
def logger(self)
Get handle to logger.
Definition: ProphecyPowhegMerge.py:225
python.ProphecyPowhegMerge.ProphecyPowhegMerge.__input_prophecy4mu_file_name
__input_prophecy4mu_file_name
Definition: ProphecyPowhegMerge.py:29
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
pickleTool.object
object
Definition: pickleTool.py:30
str
Definition: BTagTrackIpAccessor.cxx:11
error
Definition: IImpactPoint3dEstimator.h:70
python.ProphecyPowhegMerge.ProphecyPowhegMerge.merge_lhe_files
def merge_lhe_files(self, listOfFiles, outputFile)
Definition: ProphecyPowhegMerge.py:230