ATLAS Offline Software
Loading...
Searching...
No Matches
MadGraphUtils.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3# Pythonized version of MadGraph steering executables
4# written by Zach Marshall <zach.marshall@cern.ch>
5# updates for aMC@NLO by Josh McFayden <mcfayden@cern.ch>
6# updates to LHE handling and SUSY functionality by Emma Kuwertz <ekuwertz@cern.ch>
7# Attempts to remove path-dependence of MadGraph
8
9import os,time,subprocess,glob,re
10# These Import lines are temporary for backwards compatibility of clients.
11from MCJobOptionUtils.JOsupport import check_reset_proc_number # noqa: F401
12from MCJobOptionUtils.LHAPDFsupport import get_LHAPDF_DATA_PATH # noqa: F401
13from MCJobOptionUtils.LHEsupport import remap_lhe_pdgids # noqa: F401
14from MCJobOptionUtils.LHAPDFsupport import get_lhapdf_id_and_name # noqa: F401
15from MCJobOptionUtils.LHAPDFsupport import get_LHAPDF_PATHS # noqa: F401
16from MCJobOptionUtils.JOsupport import get_physics_short
17from AthenaCommon import Logging
18from MadGraphControl.MGC import MGControl
19mglog = Logging.logging.getLogger('MadGraphUtils')
20my_MGC_instance = None
21
22# Import that allows transparent migration for current users
23from MadGraphControl.MadGraphUtilsHelpers import modify_param_card # noqa: F401
24
25# Name of python executable
26python='python'
27# Magic name of gridpack directory
28MADGRAPH_GRIDPACK_LOCATION='madevent'
29# Name for the run (since we only have 1, just needs consistency)
30MADGRAPH_RUN_NAME='run_01'
31# For error handling
32MADGRAPH_CATCH_ERRORS=True
33# PDF setting (global setting)
34MADGRAPH_PDFSETTING=None
35MADGRAPH_COMMAND_STACK = []
36
37
38import shutil
39
40
41from MadGraphControl.MadGraphUtilsHelpers import error_check,get_mg5_version
42from MadGraphControl.MadGraphSystematicsUtils import systematics_run_card_options,get_pdf_and_systematic_settings
43from MadGraphControl.MadGraphParamHelpers import check_PMG_updates
44
45def stack_subprocess(command,**kwargs):
46 global MADGRAPH_COMMAND_STACK
47 MADGRAPH_COMMAND_STACK += [' '.join(command)]
48 return subprocess.Popen(command,**kwargs)
49
50def generate_prep(process_dir):
51 global MADGRAPH_COMMAND_STACK
52 if not os.access('Cards_bkup',os.R_OK):
53 shutil.copytree(process_dir+'/Cards','Cards_bkup')
54 shutil.copyfile(process_dir+'/Source/make_opts','Cards_bkup/make_opts_bkup')
55 MADGRAPH_COMMAND_STACK += ['# In case this fails, Cards_bkup should be in your original run directory']
56 MADGRAPH_COMMAND_STACK += ['# And ${MGaMC_PROCESS_DIR} can be replaced with whatever process directory exists in your stand-alone test']
57 MADGRAPH_COMMAND_STACK += ['cp '+os.getcwd()+'/Cards_bkup/*dat ${MGaMC_PROCESS_DIR}/Cards/']
58 MADGRAPH_COMMAND_STACK += ['cp '+os.getcwd()+'/Cards_bkup/make_opts_bkup ${MGaMC_PROCESS_DIR}/Source/make_opts']
59 else:
60 mglog.warning('Found Cards_bkup directory existing. Suggests you are either running generation twice (a little funny) or are not using a clean directory.')
61 bkup_v = 1
62 while os.access('Cards_bkup_'+str(bkup_v),os.R_OK) and bkup_v<100:
63 bkup_v += 1
64 if bkup_v<100:
65 shutil.copytree(process_dir+'/Cards','Cards_bkup_'+str(bkup_v))
66 shutil.copyfile(process_dir+'/Source/make_opts','Cards_bkup_'+str(bkup_v)+'/make_opts_bkup')
67 MADGRAPH_COMMAND_STACK += ['# In case this fails, Cards_bkup should be in your original run directory']
68 MADGRAPH_COMMAND_STACK += ['# And ${MGaMC_PROCESS_DIR} can be replaced with whatever process directory exists in your stand-alone test']
69 MADGRAPH_COMMAND_STACK += ['cp '+os.getcwd()+'/Cards_bkup_'+str(bkup_v)+'/*dat ${MGaMC_PROCESS_DIR}/Cards/']
70 MADGRAPH_COMMAND_STACK += ['cp '+os.getcwd()+'/Cards_bkup_'+str(bkup_v)+'/make_opts_bkup ${MGaMC_PROCESS_DIR}/Source/make_opts']
71 else:
72 mglog.warning('Way too many Cards_bkup* directories found. Giving up -- standalone script may not work.')
73
74
75def new_process(process='generate p p > t t~\noutput -f', plugin=None, keepJpegs=False, usePMGSettings=False):
76 global my_MGC_instance
77 my_MGC_instance = MGControl(process, plugin, keepJpegs, usePMGSettings)
78 return my_MGC_instance.process_dir
79
80def get_default_runcard(process_dir=MADGRAPH_GRIDPACK_LOCATION):
81 """ Copy the default runcard from one of several locations
82 to a local file with name run_card.tmp.dat"""
83 output_name = 'run_card.tmp.dat'
84
85 # Get the run card from the installation
86 run_card=process_dir+'/Cards/run_card.dat'
87 if os.access(run_card,os.R_OK):
88 mglog.info('Copying default run_card.dat from '+str(run_card))
89 shutil.copy(run_card,output_name)
90 return output_name
91 else:
92 run_card=process_dir+'/Cards/run_card_default.dat'
93 mglog.info('Fetching default run_card.dat from '+str(run_card))
94 if os.access(run_card,os.R_OK):
95 shutil.copy(run_card,output_name)
96 return output_name
97 else:
98 raise RuntimeError('Cannot find default run_card.dat or run_card_default.dat! I was looking here: %s'%run_card)
99
100
101def generate(process_dir='PROC_mssm_0', grid_pack=False, gridpack_compile=False, extlhapath=None, required_accuracy=0.01, runArgs=None, bias_module=None, requirePMGSettings=False):
102 global my_MGC_instance # noqa: F824
103
104
105 # Just in case
106 my_MGC_instance.setup_path_protection()
107
108 # Set consistent mode and number of jobs
109 mode = 0
110 njobs = 1
111 if 'ATHENA_CORE_NUMBER' in os.environ and int(os.environ['ATHENA_CORE_NUMBER'])>0:
112 njobs = int(os.environ['ATHENA_CORE_NUMBER'])
113 mglog.info('Lucky you - you are running on a full node queue. Will re-configure for '+str(njobs)+' jobs.')
114 mode = 2
115
116 cluster_type = get_cluster_type()
117 if cluster_type is not None:
118 mode = 1
119
121 mglog.info('Running event generation from gridpack (using smarter mode from generate() function)')
122 generate_from_gridpack(runArgs=runArgs,extlhapath=extlhapath,gridpack_compile=gridpack_compile,requirePMGSettings=requirePMGSettings)
123 return
124 else:
125 mglog.info('Did not identify an input gridpack.')
126 if grid_pack:
127 mglog.info('The grid_pack flag is set, so I am expecting to create a gridpack in this job')
128
129 # Now get a variety of info out of the runArgs
130 beamEnergy,random_seed = get_runArgs_info(runArgs)
131
132 # Check if process is NLO or LO
133 isNLO = my_MGC_instance.isNLO
134
135 # Setup PDF and systematics
136 setup_pdf_and_systematic_weights(MADGRAPH_PDFSETTING,my_MGC_instance.runCardDict,isNLO)
137
138
139 # temporary fix of makefile, needed for 3.3.1., remove in future
140 if isNLO:
141 fix_fks_makefile(process_dir=process_dir)
142
143 # if f2py not available
144 if get_reweight_card(process_dir=process_dir) is not None:
145 if shutil.which('f2py') is not None:
146 mglog.info('Found f2py, will use it for reweighting')
147 else:
148 raise RuntimeError('Could not find f2py, needed for reweighting')
149 check_reweight_card(process_dir)
150
151 global MADGRAPH_COMMAND_STACK
152
153 if grid_pack:
154 #Running in gridpack mode
155 mglog.info('Started generating gridpack at '+str(time.asctime()))
156 mglog.warning(' >>>>>> THIS KIND OF JOB SHOULD ONLY BE RUN LOCALLY - NOT IN GRID JOBS <<<<<<')
157
158 # Some events required if we specify MadSpin usage!
159 my_settings = {'nevents':'1000'}
160
161 if isNLO:
162 my_settings['req_acc']=str(required_accuracy)
163 else:
164 # At LO, no events are generated. That means we need to move the MS card aside and back.
165 LO_has_madspin = False
166 if os.access(f'{process_dir}/Cards/madspin_card.dat',os.R_OK):
167 MADGRAPH_COMMAND_STACK += [f'mv {process_dir}/Cards/madspin_card.dat {process_dir}/Cards/madspin_card.tmp.dat']
168 os.rename(f'{process_dir}/Cards/madspin_card.dat',f'{process_dir}/Cards/madspin_card.tmp.dat')
169 LO_has_madspin = True
170 my_settings = {'gridpack':'true'}
171 my_MGC_instance.runCardDict.update(my_settings)
172 else:
173 #Running in on-the-fly mode
174 mglog.info('Started generating at '+str(time.asctime()))
175
176 mglog.info('Run '+MADGRAPH_RUN_NAME+' will be performed in mode '+str(mode)+' with '+str(njobs)+' jobs in parallel.')
177
178 # Ensure that things are set up normally
179 if not os.access(process_dir,os.R_OK):
180 raise RuntimeError('No process directory found at '+process_dir)
181 if not os.access(process_dir+'/bin/generate_events',os.R_OK):
182 raise RuntimeError('No generate_events module found in '+process_dir)
183
184 mglog.info('For your information, the libraries available are (should include LHAPDF):')
185 ls_dir(process_dir+'/lib')
186
187 setupFastjet(process_dir=process_dir)
188 if bias_module is not None:
189 setup_bias_module(bias_module,process_dir)
190
191 mglog.info('Now I will hack the make files a bit. Apologies, but there seems to be no good way around this.')
192 shutil.copyfile(process_dir+'/Source/make_opts',process_dir+'/Source/make_opts_old')
193 old_opts = open(process_dir+'/Source/make_opts_old','r')
194 new_opts = open(process_dir+'/Source/make_opts','w')
195 for aline in old_opts:
196 if 'FC=g' in aline:
197 mglog.info('Configuring the fancy gfortran compiler instead of g77 / f77')
198 new_opts.write(' FC=gfortran\n')
199 else:
200 new_opts.write(aline)
201 old_opts.close()
202 new_opts.close()
203 mglog.info('Make file hacking complete.')
204
205 # Change directories
206 currdir=os.getcwd()
207 os.chdir(process_dir)
208 # Record the change
209 MADGRAPH_COMMAND_STACK += [ 'cd ${MGaMC_PROCESS_DIR}' ]
210
211 # Check the run card
212 my_MGC_instance.run_card_consistency_check()
213
214
215 # For grid packs we also need to move the systematics program aside
216 if grid_pack:
217 original_systematics_program = None if 'systematics_program' not in my_MGC_instance.runCardDict else my_MGC_instance.runCardDict['systematics_program']
218 my_MGC_instance.runCardDict['systematics_program'] = 'None'
219 mglog.info('systematics set to NONE')
220
221
222
223
224
225 # Check the param card
226 code = check_PMG_updates(process_dir=os.getcwd())
227 if requirePMGSettings and code!=0:
228 raise RuntimeError('Settings are not compliant with PMG defaults! Please use do_PMG_updates function to get PMG default params.')
229
230 # Build up the generate command
231 # Use the new-style way of passing things: just --name, everything else in config
232 command = [python,'bin/generate_events']
233 if isNLO:
234 command += ['--name='+MADGRAPH_RUN_NAME]
235 mglog.info('Removing Cards/shower_card.dat to ensure we get parton level events only')
236 try:
237 os.unlink('Cards/shower_card.dat')
238 except FileNotFoundError:
239 mglog.info('Cannot find Cards/shower_card.dat.')
240 else:
241 command += [MADGRAPH_RUN_NAME]
242 # Set the number of cores to be used
243 setNCores(process_dir=os.getcwd(), Ncores=njobs)
244 # Special handling for mode 1
245 if mode==1:
246 mglog.info('Setting up cluster running')
247 my_MGC_instance.configCardDict['run_mode'] = 1
248
249 if cluster_type=='pbs':
250 mglog.info('Modifying bin/internal/cluster.py for PBS cluster running')
251 os.system("sed -i \"s:text += prog:text += './'+prog:g\" bin/internal/cluster.py")
252 elif mode==2:
253 mglog.info('Setting up multi-core running on '+os.environ['ATHENA_CORE_NUMBER']+' cores')
254 elif mode==0:
255 mglog.info('Setting up serial generation.')
256
257 # Writing cards to disk
258 my_MGC_instance.write_configCard()
259 my_MGC_instance.write_runCard(runArgs=runArgs)
260
261 print_cards_from_dir(process_dir=my_MGC_instance.process_dir)
262
263
264 generate_prep(process_dir=os.getcwd())
265 generate = stack_subprocess(command,stdin=subprocess.PIPE, stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
266 (out,err) = generate.communicate()
267 error_check(err,generate.returncode)
268
269 # Get back to where we came from
270 os.chdir(currdir)
271 MADGRAPH_COMMAND_STACK += [ 'cd -' ]
272
273 if grid_pack:
274 # Name dictacted by https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/PmgMcSoftware
275 # MG version included for traceability (e.g. MG351 for version 3.5.1)
276 energy = '%1.1f'%(beamEnergy*2./1000.)
277 energy = energy.replace('.0','').replace('.','p')
278 gridpack_name='mc_'+energy+'TeV.'+get_physics_short()+'.MG'+get_mg5_version().replace('.','')+'.GRID.tar.gz'
279 mglog.info('Tidying up gridpack '+gridpack_name)
280
281 # Return the setting for the systematics_program
282 my_MGC_instance.runCardDict.update({'systematics_program':original_systematics_program})
283 # Write out run Card Dictionary
284 my_MGC_instance.write_runCard(runArgs=runArgs)
285
286 if not isNLO:
287 # At LO, no events are generated. That means we need to move the MS card aside and back.
288 if LO_has_madspin:
289 MADGRAPH_COMMAND_STACK += [f'mv {process_dir}/Cards/madspin_card.tmp.dat {process_dir}/Cards/madspin_card.dat']
290 os.rename(f'{process_dir}/Cards/madspin_card.tmp.dat',f'{process_dir}/Cards/madspin_card.dat')
291
292
293 MADGRAPH_COMMAND_STACK += ['cp '+glob.glob(process_dir+'/'+MADGRAPH_RUN_NAME+'_*gridpack.tar.gz')[0]+' '+gridpack_name]
294 shutil.copy(glob.glob(process_dir+'/'+MADGRAPH_RUN_NAME+'_*gridpack.tar.gz')[0],gridpack_name)
295
296 if gridpack_compile:
297 MADGRAPH_COMMAND_STACK += ['mkdir tmp%i/'%os.getpid(),'cd tmp%i/'%os.getpid()]
298 os.mkdir('tmp%i/'%os.getpid())
299 os.chdir('tmp%i/'%os.getpid())
300 mglog.info('untar gridpack')
301 untar = stack_subprocess(['tar','xvzf',('../'+gridpack_name)])
302 untar.wait()
303 mglog.info('compile and clean up')
304 MADGRAPH_COMMAND_STACK += ['cd madevent']
305 os.chdir('madevent/')
306 compilep = stack_subprocess(['./bin/compile'],stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
307 (out,err) = compilep.communicate()
308 error_check(err,compilep.returncode)
309 clean = stack_subprocess(['./bin/clean4grid'],stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
310 (out,err) = clean.communicate()
311 error_check(err,clean.returncode)
312 clean.wait()
313 MADGRAPH_COMMAND_STACK += ['cd ..','rm ../'+gridpack_name]
314 os.chdir('../')
315 mglog.info('remove old tarball')
316 os.unlink('../'+gridpack_name)
317 mglog.info('Package up new tarball')
318 tar = stack_subprocess(['tar','--exclude=SubProcesses/P*/G*/*_results.dat','--exclude=SubProcesses/P*/G*/*.log','--exclude=SubProcesses/P*/G*/*.txt','-cvsf','../'+gridpack_name,'.'])
319 tar.wait()
320 MADGRAPH_COMMAND_STACK += ['cd ..','rm -r tmp%i/'%os.getpid()]
321 os.chdir('../')
322 mglog.info('Remove temporary directory')
323 shutil.rmtree('tmp%i/'%os.getpid())
324 mglog.info('Tidying up complete!')
325
326 else:
327 my_MGC_instance.write_runCard(runArgs=runArgs)
328
329 mglog.info('Package up process_dir')
330 MADGRAPH_COMMAND_STACK += ['mv '+process_dir+' '+MADGRAPH_GRIDPACK_LOCATION]
331 os.rename(process_dir,MADGRAPH_GRIDPACK_LOCATION)
332 tar = stack_subprocess(['tar','--exclude=Events/*/*events*gz','--exclude=SubProcesses/P*/G*/log*txt','--exclude=SubProcesses/P*/G*/events.lhe*','--exclude=*/*.o','--exclude=*/*/*.o','--exclude=*/*/*/*.o','--exclude=*/*/*/*/*.o','-czf',gridpack_name,MADGRAPH_GRIDPACK_LOCATION])
333 tar.wait()
334 MADGRAPH_COMMAND_STACK += ['mv '+MADGRAPH_GRIDPACK_LOCATION+' '+process_dir]
335 os.rename(MADGRAPH_GRIDPACK_LOCATION,process_dir)
336
337 mglog.info('Gridpack sucessfully created, exiting the transform')
338 if hasattr(runArgs,'outputTXTFile'):
339 mglog.info('Touching output TXT (LHE) file for the transform')
340 open(runArgs.outputTXTFile, 'w').close()
341 from AthenaCommon.AppMgr import theApp
342 theApp.finalize()
343 theApp.exit()
344
345 mglog.info('Finished at '+str(time.asctime()))
346 return 0
347
348
349def generate_from_gridpack(runArgs=None, extlhapath=None, gridpack_compile=None, requirePMGSettings=False):
350 global my_MGC_instance # noqa: F824
351
352 # Get of info out of the runArgs
353 beamEnergy,random_seed = get_runArgs_info(runArgs)
354
355 # Just in case
356 my_MGC_instance.setup_path_protection()
357
358 isNLO = my_MGC_instance.isNLO
359
360 setupFastjet(process_dir=MADGRAPH_GRIDPACK_LOCATION)
361
362 # This is hard-coded as a part of MG5_aMC :'(
363 gridpack_run_name = 'GridRun_'+str(random_seed)
364
365 # Ensure that we only do madspin at the end
366 if os.access(MADGRAPH_GRIDPACK_LOCATION+'/Cards/madspin_card.dat',os.R_OK):
367 os.rename(MADGRAPH_GRIDPACK_LOCATION+'/Cards/madspin_card.dat',MADGRAPH_GRIDPACK_LOCATION+'/Cards/backup_madspin_card.dat')
368 do_madspin=True
369 else:
370 do_madspin=False
371
372 if get_reweight_card(process_dir=MADGRAPH_GRIDPACK_LOCATION) is not None:
373 check_reweight_card(MADGRAPH_GRIDPACK_LOCATION)
374
375 # Check the param card
376 code = check_PMG_updates(process_dir=MADGRAPH_GRIDPACK_LOCATION)
377 if requirePMGSettings and code!=0:
378 raise RuntimeError('Settings are not compliant with PMG defaults! Please use do_PMG_updates function to get PMG default params.')
379
380 # Modify run card, then print
381 settings={'iseed':str(random_seed)}
382 if not isNLO:
383 settings['python_seed']=str(random_seed)
384 my_MGC_instance.runCardDict.update(settings)
385
386 mglog.info('Generating events from gridpack')
387
388 # Ensure that things are set up normally
389 if not os.path.exists(MADGRAPH_GRIDPACK_LOCATION):
390 raise RuntimeError('Gridpack directory not found at '+MADGRAPH_GRIDPACK_LOCATION)
391
392 nevents = my_MGC_instance.runCardDict['nevents']
393 mglog.info('>>>> FOUND GRIDPACK <<<< <- This will be used for generation')
394 mglog.info('Generation of '+str(int(nevents))+' events will be performed using the supplied gridpack with random seed '+str(random_seed))
395 mglog.info('Started generating events at '+str(time.asctime()))
396
397 #Remove addmasses if it's there
398 if os.access(MADGRAPH_GRIDPACK_LOCATION+'/bin/internal/addmasses.py',os.R_OK):
399 os.remove(MADGRAPH_GRIDPACK_LOCATION+'/bin/internal/addmasses.py')
400
401 currdir=os.getcwd()
402
403 # Make sure we've set the number of processes appropriately
404 setNCores(process_dir=MADGRAPH_GRIDPACK_LOCATION)
405
406 # Run the consistency check, print some useful info
407 ls_dir(currdir)
408 ls_dir(MADGRAPH_GRIDPACK_LOCATION)
409
410 # Update the run card according to consistency checks
411 my_MGC_instance.run_card_consistency_check()
412
413 # Now all done with updates, so print the cards with the final settings
414 print_cards_from_dir(process_dir=MADGRAPH_GRIDPACK_LOCATION)
415
416 if isNLO:
417 #turn off systematics for gridpack generation and store settings for standalone run
418 systematics_settings=None
419 if my_MGC_instance.runCardDict.get('systematics_program',None) == 'systematics':
420 if not my_MGC_instance.runCardDict.get('store_rwgt_info',None):
421 raise RuntimeError('Trying to run NLO systematics but reweight info not stored')
422 if 'systematics_arguments' in my_MGC_instance.runCardDict:
423 systematics_settings=MadGraphControl.MadGraphSystematicsUtils.parse_systematics_arguments(my_MGC_instance.runCardDict['systematics_arguments'])
424 else:
425 systematics_settings={}
426 mglog.info('Turning off systematics for now, running standalone later')
427
428 my_MGC_instance.runCardDict['systematics_program'] = 'none'
429
430 # Writing run card to disk
431 my_MGC_instance.write_runCard(runArgs=runArgs)
432
433 global MADGRAPH_COMMAND_STACK
434 if not isNLO:
435
436 if not os.access(MADGRAPH_GRIDPACK_LOCATION+'/bin/gridrun',os.R_OK):
437 mglog.error('/bin/gridrun not found at '+MADGRAPH_GRIDPACK_LOCATION)
438 raise RuntimeError('Could not find gridrun executable')
439 else:
440 mglog.info('Found '+MADGRAPH_GRIDPACK_LOCATION+'/bin/gridrun, starting generation.')
441 generate_prep(MADGRAPH_GRIDPACK_LOCATION)
442 granularity=1
443 mglog.info("Now generating {} events with random seed {} and granularity {}".format(int(nevents),int(random_seed),granularity))
444 # not sure whether this is needed but it is done in the old "run.sh" script
445 new_ld_path=":".join([os.environ['LD_LIBRARY_PATH'],os.getcwd()+'/'+MADGRAPH_GRIDPACK_LOCATION+'/madevent/lib',os.getcwd()+'/'+MADGRAPH_GRIDPACK_LOCATION+'/HELAS/lib'])
446 os.environ['LD_LIBRARY_PATH']=new_ld_path
447 MADGRAPH_COMMAND_STACK+=["export LD_LIBRARY_PATH="+":".join(['${LD_LIBRARY_PATH}',new_ld_path])]
448 generate = stack_subprocess([python,MADGRAPH_GRIDPACK_LOCATION+'/bin/gridrun',str(int(nevents)),str(int(random_seed)),str(granularity)],stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
449 (out,err) = generate.communicate()
450 error_check(err,generate.returncode)
451 gp_events=MADGRAPH_GRIDPACK_LOCATION+"/Events/GridRun_{}/unweighted_events.lhe.gz".format(int(random_seed))
452 if not os.path.exists(gp_events):
453 mglog.error('Error in gp generation, did not find events at '+gp_events)
454
455 # add reweighting, which is not run automatically from LO GPs
456 reweight_card=get_reweight_card(MADGRAPH_GRIDPACK_LOCATION)
457 if reweight_card is not None:
458 pythonpath_backup=os.environ['PYTHONPATH']
459 # workaround as madevent crashes when path to mg in PYTHONPATH
460 os.environ['PYTHONPATH']=':'.join([p for p in pythonpath_backup.split(':') if 'madgraph5amc' not in p])
461 add_reweighting('GridRun_{}'.format(int(random_seed)))
462 os.environ['PYTHONPATH']=pythonpath_backup
463
464 shutil.move(gp_events,'events.lhe.gz')
465
466 else:
467
468 if not os.access(MADGRAPH_GRIDPACK_LOCATION+'/bin/generate_events',os.R_OK):
469 raise RuntimeError('Could not find generate_events executable at '+MADGRAPH_GRIDPACK_LOCATION)
470 else:
471 mglog.info('Found '+MADGRAPH_GRIDPACK_LOCATION+'/bin/generate_events, starting generation.')
472
473 ls_dir(MADGRAPH_GRIDPACK_LOCATION+'/Events/')
474 if os.access(MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name, os.F_OK):
475 mglog.info('Removing '+MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+' directory from gridpack generation')
476 MADGRAPH_COMMAND_STACK += ['rm -rf '+MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name]
477 shutil.rmtree(MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name)
478
479 # Delete events generated when setting up MadSpin during gridpack generation
480 if os.access(MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'_decayed_1', os.F_OK):
481 mglog.info('Removing '+MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'_decayed_1 directory from gridpack generation')
482 MADGRAPH_COMMAND_STACK += ['rm -rf '+MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'_decayed_1']
483 shutil.rmtree(MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'_decayed_1')
484
485 ls_dir(MADGRAPH_GRIDPACK_LOCATION+'/Events/')
486
487 if not gridpack_compile:
488 mglog.info('Copying make_opts from Template')
489 shutil.copy(os.environ['MADPATH']+'/Template/LO/Source/make_opts',MADGRAPH_GRIDPACK_LOCATION+'/Source/')
490
491 generate_prep(MADGRAPH_GRIDPACK_LOCATION)
492 generate = stack_subprocess([python,MADGRAPH_GRIDPACK_LOCATION+'/bin/generate_events','--parton','--nocompile','--only_generation','-f','--name='+gridpack_run_name],stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
493 (out,err) = generate.communicate()
494 error_check(err,generate.returncode)
495 else:
496 mglog.info('Allowing recompilation of gridpack')
497 if os.path.islink(MADGRAPH_GRIDPACK_LOCATION+'/lib/libLHAPDF.a'):
498 mglog.info('Unlinking '+MADGRAPH_GRIDPACK_LOCATION+'/lib/libLHAPDF.a')
499 os.unlink(MADGRAPH_GRIDPACK_LOCATION+'/lib/libLHAPDF.a')
500
501 generate_prep(MADGRAPH_GRIDPACK_LOCATION)
502 generate = stack_subprocess([python,MADGRAPH_GRIDPACK_LOCATION+'/bin/generate_events','--parton','--only_generation','-f','--name='+gridpack_run_name],stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
503 (out,err) = generate.communicate()
504 error_check(err,generate.returncode)
505 if isNLO and systematics_settings is not None:
506 # run systematics
507 mglog.info('Running systematics standalone')
508 systematics_path=MADGRAPH_GRIDPACK_LOCATION+'/bin/internal/systematics.py'
509 events_location=MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'/events.lhe.gz'
510 syst_cmd=[python,systematics_path]+[events_location]*2+["--"+k+"="+systematics_settings[k] for k in systematics_settings]
511 mglog.info('running: '+' '.join(syst_cmd))
512 systematics = stack_subprocess(syst_cmd)
513 systematics.wait()
514
515
516 # See if MG5 did the job for us already
517 if not os.access('events.lhe.gz',os.R_OK):
518 mglog.info('Copying generated events to '+currdir)
519 if not os.path.exists(MADGRAPH_GRIDPACK_LOCATION+'Events/'+gridpack_run_name):
520 shutil.copy(MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'/events.lhe.gz','events.lhe.gz')
521 else:
522 mglog.info('Events were already in place')
523
524 ls_dir(currdir)
525
526 mglog.info('Moving generated events to be in correct format for arrange_output().')
527 mglog.info('Unzipping generated events.')
528 unzip = stack_subprocess(['gunzip','-f','events.lhe.gz'])
529 unzip.wait()
530
531 mglog.info('Moving file over to '+MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'/unweighted_events.lhe')
532 mkdir = stack_subprocess(['mkdir','-p',(MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name)])
533 mkdir.wait()
534 shutil.move('events.lhe',MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'/unweighted_events.lhe')
535
536 mglog.info('Re-zipping into dataset name '+MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'/unweighted_events.lhe.gz')
537 rezip = stack_subprocess(['gzip',MADGRAPH_GRIDPACK_LOCATION+'/Events/'+gridpack_run_name+'/unweighted_events.lhe'])
538 rezip.wait()
539
540 os.chdir(currdir)
541
542 # Now consider MadSpin:
543 if do_madspin:
544 # Move card back
545 os.rename(MADGRAPH_GRIDPACK_LOCATION+'/Cards/backup_madspin_card.dat',MADGRAPH_GRIDPACK_LOCATION+'/Cards/madspin_card.dat')
546 mglog.info('Decaying with MadSpin.')
547 add_madspin(process_dir=MADGRAPH_GRIDPACK_LOCATION)
548
549 mglog.info('Finished at '+str(time.asctime()))
550
551 return 0
552
553
554def setupFastjet(process_dir=None):
555 global my_MGC_instance # noqa: F824
556
557 isNLO = my_MGC_instance.isNLO
558
559 mglog.info('Path to fastjet install dir: '+os.environ['FASTJETPATH'])
560 fastjetconfig = os.environ['FASTJETPATH']+'/bin/fastjet-config'
561
562 mglog.info('fastjet-config --version: '+str(subprocess.Popen([fastjetconfig, '--version'],stdout = subprocess.PIPE).stdout.read().strip()))
563 mglog.info('fastjet-config --prefix: '+str(subprocess.Popen([fastjetconfig, '--prefix'],stdout = subprocess.PIPE).stdout.read().strip()))
564
565 if not isNLO:
566 config_card=process_dir+'/Cards/me5_configuration.txt'
567 else:
568 config_card=process_dir+'/Cards/amcatnlo_configuration.txt'
569
570 oldcard = open(config_card,'r')
571 newcard = open(config_card+'.tmp','w')
572
573 for line in oldcard:
574 if 'fastjet = ' in line:
575 newcard.write('fastjet = '+fastjetconfig+'\n')
576 mglog.info('Setting fastjet = '+fastjetconfig+' in '+config_card)
577 else:
578 newcard.write(line)
579 oldcard.close()
580 newcard.close()
581 shutil.move(config_card+'.tmp',config_card)
582
583 return
584
585def get_runArgs_info(runArgs):
586 """This is a temporary function that returns the beam energy and random seed from runArgs,
587 as more functions move to the MGControl class this will not be necessary
588 """
589 global my_MGC_instance # noqa: F824
590 #check if the function has already been called
591 if my_MGC_instance.beamEnergy == 0: #if beamEnergy is 0, it hasn't been set yet so we will call the class function.
592 my_MGC_instance.get_runArgs_info(runArgs)
593 #return the beam energy and the random seeed
594 return my_MGC_instance.beamEnergy, my_MGC_instance.random_seed
595
596
597def setupLHAPDF(process_dir=None, extlhapath=None, allow_links=True):
598 global my_MGC_instance # noqa: F824
599
600 isNLO = my_MGC_instance.isNLO
601
602 origLHAPATH=os.environ['LHAPATH']
603 origLHAPDF_DATA_PATH=os.environ['LHAPDF_DATA_PATH']
604
605 LHAPATH,LHADATAPATH=get_LHAPDF_PATHS()
606
607 pdfname=''
608 pdfid=-999
609
610
611 mydict= my_MGC_instance.runCardDict
612 if mydict["pdlabel"].replace("'","") == 'lhapdf':
613 #Make local LHAPDF dir
614 mglog.info('creating local LHAPDF dir: MGC_LHAPDF/')
615 if os.path.islink('MGC_LHAPDF/'):
616 os.unlink('MGC_LHAPDF/')
617 elif os.path.isdir('MGC_LHAPDF/'):
618 shutil.rmtree('MGC_LHAPDF/')
619
620 newMGCLHA='MGC_LHAPDF/'
621
622 mkdir = subprocess.Popen(['mkdir','-p',newMGCLHA])
623 mkdir.wait()
624
625 pdfs_used=[ int(x) for x in mydict['lhaid'].replace(' ',',').split(',') ]
626 # included systematics pdfs here
627 if 'sys_pdf' in mydict:
628 sys_pdf=mydict['sys_pdf'].replace('&&',' ').split()
629 for s in sys_pdf:
630 if s.isdigit():
631 idx=int(s)
632 if idx>1000: # the sys_pdf syntax is such that small numbers are used to specify the subpdf index
633 pdfs_used.append(idx)
634 else:
635 pdfs_used.append(s)
636 if 'systematics_arguments' in mydict:
637 systematics_arguments=MadGraphControl.MadGraphSystematicsUtils.parse_systematics_arguments(mydict['systematics_arguments'])
638 if 'pdf' in systematics_arguments:
639 sys_pdf=systematics_arguments['pdf'].replace(',',' ').replace('@',' ').split()
640 for s in sys_pdf:
641 if s.isdigit():
642 idx=int(s)
643 if idx>1000: # the sys_pdf syntax is such that small numbers are used to specify the subpdf index
644 pdfs_used.append(idx)
645 else:
646 pdfs_used.append(s)
647 for pdf in pdfs_used:
648 if isinstance(pdf,str) and (pdf.lower()=='errorset' or pdf.lower()=='central'):
649 continue
650 # new function to get both lhapdf id and name
651 pdfid,pdfname=get_lhapdf_id_and_name(pdf)
652 mglog.info("Found LHAPDF ID="+str(pdfid)+", name="+pdfname)
653
654 if not os.path.exists(newMGCLHA+pdfname) and not os.path.lexists(newMGCLHA+pdfname):
655 if not os.path.exists(LHADATAPATH+'/'+pdfname):
656 mglog.warning('PDF not installed at '+LHADATAPATH+'/'+pdfname)
657 if allow_links:
658 mglog.info('linking '+LHADATAPATH+'/'+pdfname+' --> '+newMGCLHA+pdfname)
659 os.symlink(LHADATAPATH+'/'+pdfname,newMGCLHA+pdfname)
660 else:
661 mglog.info('copying '+LHADATAPATH+'/'+pdfname+' --> '+newMGCLHA+pdfname)
662 shutil.copytree(LHADATAPATH+'/'+pdfname,newMGCLHA+pdfname)
663
664 if allow_links:
665 mglog.info('linking '+LHADATAPATH+'/pdfsets.index --> '+newMGCLHA+'pdfsets.index')
666 os.symlink(LHADATAPATH+'/pdfsets.index',newMGCLHA+'pdfsets.index')
667
668 atlasLHADATAPATH=LHADATAPATH.replace('sft.cern.ch/lcg/external/lhapdfsets/current','atlas.cern.ch/repo/sw/Generators/lhapdfsets/current')
669 mglog.info('linking '+atlasLHADATAPATH+'/lhapdf.conf --> '+newMGCLHA+'lhapdf.conf')
670 os.symlink(atlasLHADATAPATH+'/lhapdf.conf',newMGCLHA+'lhapdf.conf')
671 else:
672 mglog.info('copying '+LHADATAPATH+'/pdfsets.index --> '+newMGCLHA+'pdfsets.index')
673 shutil.copy2(LHADATAPATH+'/pdfsets.index',newMGCLHA+'pdfsets.index')
674
675 atlasLHADATAPATH=LHADATAPATH.replace('sft.cern.ch/lcg/external/lhapdfsets/current','atlas.cern.ch/repo/sw/Generators/lhapdfsets/current')
676 mglog.info('copying '+atlasLHADATAPATH+'/lhapdf.conf -->'+newMGCLHA+'lhapdf.conf')
677 shutil.copy2(atlasLHADATAPATH+'/lhapdf.conf',newMGCLHA+'lhapdf.conf')
678
679
680 LHADATAPATH=os.getcwd()+'/MGC_LHAPDF'
681
682 else:
683 mglog.info('Not using LHAPDF')
684 return (LHAPATH,origLHAPATH,origLHAPDF_DATA_PATH)
685
686
687 if isNLO:
688 os.environ['LHAPDF_DATA_PATH']=LHADATAPATH
689
690 mglog.info('Path to LHAPDF install dir: '+LHAPATH)
691 mglog.info('Path to LHAPDF data dir: '+LHADATAPATH)
692 if not os.path.isdir(LHADATAPATH):
693 raise RuntimeError('LHAPDF data dir not accesible: '+LHADATAPATH)
694 if not os.path.isdir(LHAPATH):
695 raise RuntimeError('LHAPDF path dir not accesible: '+LHAPATH)
696
697 # Dealing with LHAPDF
698 if extlhapath:
699 lhapdfconfig=extlhapath
700 if not os.access(lhapdfconfig,os.X_OK):
701 raise RuntimeError('Failed to find valid external lhapdf-config at '+lhapdfconfig)
702 LHADATAPATH=subprocess.Popen([lhapdfconfig, '--datadir'],stdout = subprocess.PIPE).stdout.read().strip()
703 mglog.info('Changing LHAPDF_DATA_PATH to '+LHADATAPATH)
704 os.environ['LHAPDF_DATA_PATH']=LHADATAPATH
705 else:
706 getlhaconfig = subprocess.Popen(['get_files','-data','lhapdf-config'])
707 getlhaconfig.wait()
708 #Get custom lhapdf-config
709 if not os.access(os.getcwd()+'/lhapdf-config',os.X_OK):
710 mglog.error('Failed to get lhapdf-config from MadGraphControl')
711 return 1
712 lhapdfconfig = os.getcwd()+'/lhapdf-config'
713
714 mglog.info('lhapdf-config --version: '+str(subprocess.Popen([lhapdfconfig, '--version'],stdout = subprocess.PIPE).stdout.read().strip()))
715 mglog.info('lhapdf-config --prefix: '+str(subprocess.Popen([lhapdfconfig, '--prefix'],stdout = subprocess.PIPE).stdout.read().strip()))
716 mglog.info('lhapdf-config --libdir: '+str(subprocess.Popen([lhapdfconfig, '--libdir'],stdout = subprocess.PIPE).stdout.read().strip()))
717 mglog.info('lhapdf-config --datadir: '+str(subprocess.Popen([lhapdfconfig, '--datadir'],stdout = subprocess.PIPE).stdout.read().strip()))
718 mglog.info('lhapdf-config --pdfsets-path: '+str(subprocess.Popen([lhapdfconfig, '--pdfsets-path'],stdout = subprocess.PIPE).stdout.read().strip()))
719
720
721 my_MGC_instance.configCardDict.update({'lhapdf':lhapdfconfig,'lhapdf_py3':lhapdfconfig})
722
723 mglog.info('Creating links for LHAPDF')
724 if os.path.islink(process_dir+'/lib/PDFsets'):
725 os.unlink(process_dir+'/lib/PDFsets')
726 elif os.path.isdir(process_dir+'/lib/PDFsets'):
727 shutil.rmtree(process_dir+'/lib/PDFsets')
728 if allow_links:
729 os.symlink(LHADATAPATH,process_dir+'/lib/PDFsets')
730 else:
731 shutil.copytree(LHADATAPATH,process_dir+'/lib/PDFsets')
732 mglog.info('Available PDFs are:')
733 mglog.info( sorted( [ x for x in os.listdir(process_dir+'/lib/PDFsets') if ".tar.gz" not in x ] ) )
734
735 global MADGRAPH_COMMAND_STACK
736 MADGRAPH_COMMAND_STACK += [ '# Copy the LHAPDF files locally' ]
737 MADGRAPH_COMMAND_STACK += [ 'cp -r '+os.getcwd()+'/MGC_LHAPDF .' ]
738 MADGRAPH_COMMAND_STACK += [ 'cp -r '+process_dir+'/lib/PDFsets ${MGaMC_PROCESS_DIR}/lib/' ]
739
740 return (LHAPATH,origLHAPATH,origLHAPDF_DATA_PATH)
741
742
743# Function to set the number of cores and the running mode in the run card
744def setNCores(process_dir, Ncores=None):
745 global my_MGC_instance # noqa: F824
746
747 my_Ncores = Ncores
748 my_runMode = 2 if 'ATHENA_CORE_NUMBER' in os.environ else 0
749 if Ncores is None and 'ATHENA_CORE_NUMBER' in os.environ and int(os.environ['ATHENA_CORE_NUMBER'])>0:
750 my_Ncores = int(os.environ['ATHENA_CORE_NUMBER'])
751 my_runMode = 2
752 if my_Ncores is None:
753 mglog.info('Setting up for serial run')
754 my_Ncores = 1
755 my_MGC_instance.configCardDict.update({'nb_core':my_Ncores,'run_mode':my_runMode,'automatic_html_opening':'False'})
756
757
758
759
760
761
763 madpath=os.environ['MADPATH']
764 if not os.access(madpath+'/bin/mg5_aMC',os.R_OK):
765 raise RuntimeError('mg5_aMC executable not found in '+madpath)
766 return madpath+'/bin/mg5_aMC'
767
768
769def add_lifetimes(process_dir,threshold=None):
770 """ Add lifetimes to the generated LHE file. Should be
771 called after generate_events is called.
772 """
773
774 me_exec=get_mg5_executable()
775
776 if len(glob.glob(process_dir+'/Events/*'))<1:
777 mglog.error('Process dir '+process_dir+' does not contain events?')
778 run = glob.glob(process_dir+'/Events/*')[0].split('/')[-1]
779
780 # Note : This slightly clunky implementation is needed for the time being
781 # See : https://answers.launchpad.net/mg5amcnlo/+question/267904
782
783 tof_c = open('time_of_flight_exec_card','w')
784 tof_c.write('launch '+process_dir+''' -i
785add_time_of_flight '''+run+((' --threshold='+str(threshold)) if threshold is not None else ''))
786 tof_c.close()
787
788 mglog.info('Started adding time of flight info '+str(time.asctime()))
789
790 generate = stack_subprocess([python,me_exec,'time_of_flight_exec_card'],stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
791 (out,err) = generate.communicate()
792 error_check(err,generate.returncode)
793
794 mglog.info('Finished adding time of flight information at '+str(time.asctime()))
795
796 # Re-zip the file if needed
797 lhe_gz = glob.glob(process_dir+'/Events/*/*lhe.gz')[0]
798 if not os.access(lhe_gz,os.R_OK):
799 mglog.info('LHE file needs to be zipped')
800 lhe = glob.glob(process_dir+'/Events/*/*lhe.gz')[0]
801 rezip = stack_subprocess(['gzip',lhe])
802 rezip.wait()
803 mglog.info('Zipped')
804 else:
805 mglog.info('LHE file zipped by MadGraph automatically. Nothing to do')
806
807 return True
808
809
810def add_madspin(madspin_card=None,process_dir=MADGRAPH_GRIDPACK_LOCATION):
811 """ Run madspin on the generated LHE file. Should be
812 run when you have inputGeneratorFile set.
813 Only requires a simplified process with the same model that you are
814 interested in (needed to set up a process directory for MG5_aMC)
815 """
816
817 me_exec=get_mg5_executable()
818
819 if madspin_card is not None:
820 shutil.copyfile(madspin_card,process_dir+'/Cards/madspin_card.dat')
821
822 if len(glob.glob(process_dir+'/Events/*'))<1:
823 mglog.error('Process dir '+process_dir+' does not contain events?')
824 proc_dir_list = glob.glob(process_dir+'/Events/*')
825 run=None
826 for adir in proc_dir_list:
827 if 'GridRun_' in adir:
828 run=adir.split('/')[-1]
829 break
830 else:
831 run=proc_dir_list[0].split('/')[-1]
832
833 # Note : This slightly clunky implementation is needed for the time being
834 # See : https://answers.launchpad.net/mg5amcnlo/+question/267904
835
836 ms_c = open('madspin_exec_card','w')
837 ms_c.write('launch '+process_dir+''' -i
838decay_events '''+run)
839 ms_c.close()
840
841 mglog.info('Started running madspin at '+str(time.asctime()))
842
843 generate = stack_subprocess([python,me_exec,'madspin_exec_card'],stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
844 (out,err) = generate.communicate()
845 error_check(err,generate.returncode)
846 if len(glob.glob(process_dir+'/Events/'+run+'_decayed_*/')) == 0:
847 mglog.error('No '+process_dir+'/Events/'+run+'_decayed_*/ can be found')
848 raise RuntimeError('Problem while running MadSpin')
849
850 mglog.info('Finished running madspin at '+str(time.asctime()))
851
852 # Re-zip the file if needed
853 lhe_gz = glob.glob(process_dir+'/Events/*/*lhe.gz')[0]
854 if not os.access(lhe_gz,os.R_OK):
855 mglog.info('LHE file needs to be zipped')
856 lhe = glob.glob(process_dir+'/Events/*/*lhe.gz')[0]
857 rezip = stack_subprocess(['gzip',lhe])
858 rezip.wait()
859 mglog.info('Zipped')
860 else:
861 mglog.info('LHE file zipped by MadGraph automatically. Nothing to do')
862
863
864def madspin_on_lhe(input_LHE,madspin_card,runArgs=None,keep_original=False):
865 """ Run MadSpin on an input LHE file. Takes the process
866 from the LHE file, so you don't need to have a process directory
867 set up in advance. Runs MadSpin and packs the LHE file up appropriately
868 Needs runArgs for the file handling"""
869 if not os.access(input_LHE,os.R_OK):
870 raise RuntimeError('Could not find LHE file '+input_LHE)
871 if not os.access(madspin_card,os.R_OK):
872 raise RuntimeError('Could not find input MadSpin card '+madspin_card)
873 if keep_original:
874 shutil.copy(input_LHE,input_LHE+'.original')
875 mglog.info('Put backup copy of LHE file at '+input_LHE+'.original')
876 # Start writing the card for execution
877 madspin_exec_card = open('madspin_exec_card','w')
878 madspin_exec_card.write('import '+input_LHE+'\n')
879 # Based on the original card
880 input_madspin_card = open(madspin_card,'r')
881 has_launch = False
882 for l in input_madspin_card.readlines():
883 commands = l.split('#')[0].split()
884 # Skip import of a file name that isn't our file
885 if len(commands)>1 and 'import'==commands[0] and not 'model'==commands[1]:
886 continue
887 # Check for a launch command
888 if len(commands)>0 and 'launch' == commands[0]:
889 has_launch = True
890 madspin_exec_card.write(l.strip()+'\n')
891 if not has_launch:
892 madspin_exec_card.write('launch\n')
893 madspin_exec_card.close()
894 input_madspin_card.close()
895 # Now get the madspin executable
896 madpath=os.environ['MADPATH']
897 if not os.access(madpath+'/MadSpin/madspin',os.R_OK):
898 raise RuntimeError('madspin executable not found in '+madpath)
899 mglog.info('Starting madspin at '+str(time.asctime()))
900 generate = stack_subprocess([python,madpath+'/MadSpin/madspin','madspin_exec_card'],stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
901 (out,err) = generate.communicate()
902 error_check(err,generate.returncode)
903 mglog.info('Done with madspin at '+str(time.asctime()))
904 # Should now have a re-zipped LHE file
905 # We now have to do a shortened version of arrange_output below
906 # Clean up in case a link or file was already there
907 if os.path.exists(os.getcwd()+'/events.lhe'):
908 os.remove(os.getcwd()+'/events.lhe')
909
910 mglog.info('Unzipping generated events.')
911 unzip = stack_subprocess(['gunzip','-f',input_LHE+'.gz'])
912 unzip.wait()
913
914 mglog.info('Putting a copy in place for the transform.')
915 mod_output = open(os.getcwd()+'/events.lhe','w')
916
917 #Removing empty lines in LHE
918 nEmpty=0
919 with open(input_LHE,'r') as fileobject:
920 for line in fileobject:
921 if line.strip():
922 mod_output.write(line)
923 else:
924 nEmpty=nEmpty+1
925 mod_output.close()
926
927 mglog.info('Removed '+str(nEmpty)+' empty lines from LHEF')
928
929 # Actually move over the dataset - this first part is horrible...
930 if runArgs is None:
931 raise RuntimeError('Must provide runArgs to madspin_on_lhe')
932
933 outputDS = runArgs.outputTXTFile if hasattr(runArgs,'outputTXTFile') else 'tmp_LHE_events.tar.gz'
934
935 mglog.info('Moving file over to '+outputDS.split('.tar.gz')[0]+'.events')
936 shutil.move(os.getcwd()+'/events.lhe',outputDS.split('.tar.gz')[0]+'.events')
937
938 mglog.info('Re-zipping into dataset name '+outputDS)
939 rezip = stack_subprocess(['tar','cvzf',outputDS,outputDS.split('.tar.gz')[0]+'.events'])
940 rezip.wait()
941
942 # shortening the outputDS in the case of an output TXT file
943 if hasattr(runArgs,'outputTXTFile') and runArgs.outputTXTFile is not None:
944 outputDS = outputDS.split('.TXT')[0]
945 # Do some fixing up for them
946 if runArgs is not None:
947 mglog.debug('Setting inputGenerator file to '+outputDS)
948 runArgs.inputGeneratorFile=outputDS
949
950
951def arrange_output(process_dir=MADGRAPH_GRIDPACK_LOCATION,lhe_version=None,saveProcDir=False,runArgs=None,fixEventWeightsForBridgeMode=False):
952
953 # NLO is not *really* the question here, we need to know if we should look for weighted or
954 # unweighted events in the output directory. MadSpin (above) only seems to give weighted
955 # results for now?
956 if len(glob.glob(os.path.join(process_dir, 'Events','*')))<1:
957 mglog.error('Process dir '+process_dir+' does not contain events?')
958 proc_dir_list = glob.glob(os.path.join(process_dir, 'Events', '*'))
959 this_run_name=None
960 # looping over possible directories to find the right one
961 for adir in proc_dir_list:
962 if 'decayed' in adir:# skipping '*decayed*' directories produced by MadSpin, will be picked later if they exist
963 continue
964 else:
965 if 'GridRun_' in adir:
966 this_run_name=adir
967 break # GridRun_* directories have priority
968 elif os.path.join(process_dir, 'Events',MADGRAPH_RUN_NAME) in adir:
969 this_run_name=adir
970 if not os.access(this_run_name,os.R_OK):
971 raise RuntimeError('Unable to locate run directory')
972
973 hasUnweighted = os.access(this_run_name+'/unweighted_events.lhe.gz',os.R_OK)
974
975 hasRunMadSpin=False
976 madspinDirs=sorted(glob.glob(this_run_name+'_decayed_*/'))
977 if len(madspinDirs):
978 hasRunMadSpin=True
979 if hasRunMadSpin and not hasUnweighted:
980 # check again:
981 hasUnweighted = os.access(madspinDirs[-1]+'/unweighted_events.lhe.gz',os.R_OK)
982
983 global MADGRAPH_COMMAND_STACK
984 if hasRunMadSpin:
985 if len(madspinDirs):
986 if hasUnweighted:
987 # so this is a bit of a mess now...
988 # if madspin is run from an NLO grid pack the correct lhe events are at both
989 # madevent/Events/run_01/unweighted_events.lhe.gz
990 # and madevent/Events/run_01_decayed_1/events.lhe.gz
991 # so there are unweighted events but not in the madspinDir...
992 if os.path.exists(madspinDirs[-1]+'/unweighted_events.lhe.gz'):
993 MADGRAPH_COMMAND_STACK += ['mv '+madspinDirs[-1]+'/unweighted_events.lhe.gz'+' '+this_run_name+'/unweighted_events.lhe.gz']
994 shutil.move(madspinDirs[-1]+'/unweighted_events.lhe.gz',this_run_name+'/unweighted_events.lhe.gz')
995 mglog.info('Moving MadSpin events from '+madspinDirs[-1]+'/unweighted_events.lhe.gz to '+this_run_name+'/unweighted_events.lhe.gz')
996 elif os.path.exists(madspinDirs[-1]+'/events.lhe.gz'):
997 MADGRAPH_COMMAND_STACK += ['mv '+madspinDirs[-1]+'/events.lhe.gz'+' '+this_run_name+'/unweighted_events.lhe.gz']
998 shutil.move(madspinDirs[-1]+'/events.lhe.gz',this_run_name+'/unweighted_events.lhe.gz')
999 mglog.info('Moving MadSpin events from '+madspinDirs[-1]+'/events.lhe.gz to '+this_run_name+'/unweighted_events.lhe.gz')
1000 else:
1001 raise RuntimeError('MadSpin was run but can\'t find files :(')
1002
1003 else:
1004 MADGRAPH_COMMAND_STACK += ['mv '+madspinDirs[-1]+'/events.lhe.gz '+this_run_name+'/events.lhe.gz']
1005 shutil.move(madspinDirs[-1]+'/events.lhe.gz',this_run_name+'/events.lhe.gz')
1006 mglog.info('Moving MadSpin events from '+madspinDirs[-1]+'/events.lhe.gz to '+this_run_name+'/events.lhe.gz')
1007
1008 else:
1009 mglog.error('MadSpin was run but can\'t find output folder '+(this_run_name+'_decayed_1/'))
1010 raise RuntimeError('MadSpin was run but can\'t find output folder '+(this_run_name+'_decayed_1/'))
1011
1012 if fixEventWeightsForBridgeMode:
1013 mglog.info("Fixing event weights after MadSpin... initial checks.")
1014
1015 # get the cross section from the undecayed LHE file
1016 spinmodenone=False
1017 MGnumevents=-1
1018 MGintweight=-1
1019
1020 if hasUnweighted:
1021 eventsfilename="unweighted_events"
1022 else:
1023 eventsfilename="events"
1024 unzip = stack_subprocess(['gunzip','-f',this_run_name+'/%s.lhe.gz' % eventsfilename])
1025 unzip.wait()
1026
1027 for line in open(process_dir+'/Events/'+MADGRAPH_RUN_NAME+'/%s.lhe'%eventsfilename):
1028 if "Number of Events" in line:
1029 sline=line.split()
1030 MGnumevents=int(sline[-1])
1031 elif "Integrated weight (pb)" in line:
1032 sline=line.split()
1033 MGintweight=float(sline[-1])
1034 elif "set spinmode none" in line:
1035 spinmodenone=True
1036 elif "</header>" in line:
1037 break
1038
1039 if spinmodenone and MGnumevents>0 and MGintweight>0:
1040 mglog.info("Fixing event weights after MadSpin... modifying LHE file.")
1041 newlhe=open(this_run_name+'/%s_fixXS.lhe'%eventsfilename,'w')
1042 initlinecount=0
1043 eventlinecount=0
1044 inInit=False
1045 inEvent=False
1046
1047 # new default for MG 2.6.1+ (https://its.cern.ch/jira/browse/AGENE-1725)
1048 # but verified from LHE below.
1049 event_norm_setting="average"
1050
1051 for line in open(this_run_name+'/%s.lhe'%eventsfilename):
1052
1053 newline=line
1054 if "<init>" in line:
1055 inInit=True
1056 initlinecount=0
1057 elif "</init>" in line:
1058 inInit=False
1059 elif inInit and initlinecount==0:
1060 initlinecount=1
1061 # check event_norm setting in LHE file, deteremines how Pythia interprets event weights
1062 sline=line.split()
1063 if abs(int(sline[-2])) == 3:
1064 event_norm_setting="sum"
1065 elif abs(int(sline[-2])) == 4:
1066 event_norm_setting="average"
1067 elif inInit and initlinecount==1:
1068 sline=line.split()
1069 # update the global XS info
1070 relunc=float(sline[1])/float(sline[0])
1071 sline[0]=str(MGintweight)
1072 sline[1]=str(float(sline[0])*relunc)
1073 if event_norm_setting=="sum":
1074 sline[2]=str(MGintweight/MGnumevents)
1075 elif event_norm_setting=="average":
1076 sline[2]=str(MGintweight)
1077 newline=' '.join(sline)
1078 newline+="\n"
1079 initlinecount+=1
1080 elif inInit and initlinecount>1:
1081 initlinecount+=1
1082 elif "<event>" in line:
1083 inEvent=True
1084 eventlinecount=0
1085 elif "</event>" in line:
1086 inEvent=False
1087 elif inEvent and eventlinecount==0:
1088 sline=line.split()
1089 # next change the per-event weights
1090 if event_norm_setting=="sum":
1091 sline[2]=str(MGintweight/MGnumevents)
1092 elif event_norm_setting=="average":
1093 sline[2]=str(MGintweight)
1094 newline=' '.join(sline)
1095 newline+="\n"
1096 eventlinecount+=1
1097 newlhe.write(newline)
1098 newlhe.close()
1099
1100 mglog.info("Fixing event weights after MadSpin... cleaning up.")
1101 shutil.copyfile(this_run_name+'/%s.lhe' % eventsfilename,
1102 this_run_name+'/%s_badXS.lhe' % eventsfilename)
1103
1104 shutil.move(this_run_name+'/%s_fixXS.lhe' % eventsfilename,
1105 this_run_name+'/%s.lhe' % eventsfilename)
1106
1107 rezip = stack_subprocess(['gzip',this_run_name+'/%s.lhe' % eventsfilename])
1108 rezip.wait()
1109
1110 rezip = stack_subprocess(['gzip',this_run_name+'/%s_badXS.lhe' % eventsfilename])
1111 rezip.wait()
1112
1113 # Clean up in case a link or file was already there
1114 if os.path.exists(os.getcwd()+'/events.lhe'):
1115 os.remove(os.getcwd()+'/events.lhe')
1116
1117 mglog.info('Unzipping generated events.')
1118 if hasUnweighted:
1119 unzip = stack_subprocess(['gunzip','-f',this_run_name+'/unweighted_events.lhe.gz'])
1120 unzip.wait()
1121 else:
1122 unzip = stack_subprocess(['gunzip','-f',this_run_name+'/events.lhe.gz'])
1123 unzip.wait()
1124
1125 mglog.info('Putting a copy in place for the transform.')
1126 if hasUnweighted:
1127 orig_input = this_run_name+'/unweighted_events.lhe'
1128 mod_output = open(os.getcwd()+'/events.lhe','w')
1129 else:
1130 orig_input = this_run_name+'/events.lhe'
1131 mod_output = open(os.getcwd()+'/events.lhe','w')
1132
1133 #Removing empty lines and bad comments in LHE
1134 #and check for existence of weights
1135 initrwgt=None
1136 nEmpty=0
1137 lhe_weights=[]
1138 with open(orig_input,'r') as fileobject:
1139 for line in fileobject:
1140 if line.strip():
1141 # search for bad characters (neccessary until at least MG5 2.8.1)
1142 newline=line
1143 if '#' not in newline:
1144 newline=newline
1145 elif '>' not in newline[ newline.find('#'): ]:
1146 newline=newline
1147 else:
1148 mglog.info('Found bad LHE line with an XML mark in a comment: "'+newline.strip()+'"')
1149 newline=newline[:newline.find('#')]+'#'+ (newline[newline.find('#'):].replace('>','-'))
1150 # check for weightnames that should exist, simplify nominal weight names
1151 if initrwgt is False:
1152 pass
1153 elif "</initrwgt>" in newline:
1154 initrwgt=False
1155 elif "<initrwgt>" in newline:
1156 initrwgt=True
1157 elif initrwgt is not None:
1158 newline=newline.replace('_DYNSCALE-1','')
1159 if '</weight>' in newline:
1160 iend=newline.find('</weight>')
1161 istart=newline[:iend].rfind('>')
1162 lhe_weights+=[newline[istart+1:iend].strip()]
1163 mod_output.write(newline)
1164 else:
1165 nEmpty=nEmpty+1
1166 mod_output.close()
1167 mglog.info('Removed '+str(nEmpty)+' empty lines from LHEF')
1168
1169 mglog.info("The following "+str(len(lhe_weights))+" weights have been written to the LHE file: "+",".join(lhe_weights))
1170 expected_weights=get_expected_reweight_names(get_reweight_card(process_dir))
1171 expected_weights+=get_expected_systematic_names(MADGRAPH_PDFSETTING)
1172 mglog.info("Checking whether the following expected weights are in LHE file: "+",".join(expected_weights))
1173 for w in expected_weights:
1174 if w not in lhe_weights:
1175 raise RuntimeError("Did not find expected weight "+w+" in lhe file. Did the reweight or systematics module crash?")
1176 mglog.info("Found all required weights!")
1177
1178 if lhe_version:
1179 mod_output2 = open(os.getcwd()+'/events.lhe','r')
1180 test=mod_output2.readline()
1181 if 'version="' in test:
1182 mglog.info('Applying LHE version hack')
1183 final_file = open(os.getcwd()+'/events.lhe.copy','w')
1184 final_file.write('<LesHouchesEvents version="%i.0">\n'%lhe_version)
1185 shutil.copyfileobj(mod_output2, final_file)
1186 final_file.close()
1187 shutil.copy(os.getcwd()+'/events.lhe.copy',os.getcwd()+'/events.lhe')
1188 # Clean up after ourselves
1189 os.remove(os.getcwd()+'/events.lhe.copy')
1190 mod_output2.close()
1191
1192 # Actually move over the dataset
1193 if runArgs is None:
1194 raise RuntimeError('Must provide runArgs to arrange_output')
1195
1196 if hasattr(runArgs,'outputTXTFile'):
1197 outputDS = runArgs.outputTXTFile
1198 else:
1199 outputDS = 'tmp_LHE_events.tar.gz'
1200
1201 mglog.info('Moving file over to '+outputDS.split('.tar.gz')[0]+'.events')
1202
1203 shutil.move(os.getcwd()+'/events.lhe',outputDS.split('.tar.gz')[0]+'.events')
1204
1205 mglog.info('Re-zipping into dataset name '+outputDS)
1206 rezip = stack_subprocess(['tar','cvzf',outputDS,outputDS.split('.tar.gz')[0]+'.events'])
1207 rezip.wait()
1208
1209 if not saveProcDir:
1210 mglog.info('Removing the process directory')
1211 shutil.rmtree(process_dir,ignore_errors=True)
1212
1213 if os.path.isdir('MGC_LHAPDF/'):
1214 shutil.rmtree('MGC_LHAPDF/',ignore_errors=True)
1215
1216 # shortening the outputDS in the case of an output TXT file
1217 if hasattr(runArgs,'outputTXTFile') and runArgs.outputTXTFile is not None:
1218 outputDS = outputDS.split('.TXT')[0]
1219 # Do some fixing up for them
1220 if runArgs is not None:
1221 mglog.debug('Setting inputGenerator file to '+outputDS)
1222 runArgs.inputGeneratorFile=outputDS
1223
1224 mglog.info('All done with output arranging!')
1225 return outputDS
1226
1227def get_expected_reweight_names(reweight_card_loc):
1228 if reweight_card_loc is None:
1229 return []
1230 names=[]
1231 f_rw=open(reweight_card_loc)
1232 for line in f_rw:
1233 if 'launch' not in line:
1234 continue
1235 match=re.match(r'launch.*--rwgt_info\s*=\s*(\S+).*',line.strip())
1236 if len(match.groups())!=1:
1237 raise RuntimeError('Unexpected format of reweight card in line'+line)
1238 else:
1239 names+=[match.group(1)]
1240 f_rw.close()
1241 return names
1242
1244 names=[]
1245 if syst_setting is None or 'central_pdf' not in syst_setting:
1246 mglog.warning("Systematics have not been defined via base fragment or 'MADGRAPH_PDFSETTING', cannot check for expected weights")
1247 return []
1248 if 'pdf_variations' in syst_setting and isinstance(syst_setting['pdf_variations'],list):
1249 names+=[MadGraphControl.MadGraphSystematicsUtils.SYSTEMATICS_WEIGHT_INFO%{'mur':1.0,'muf':1.0,'pdf':syst_setting['central_pdf']}]
1250 for pdf in syst_setting['pdf_variations']:
1251 names+=[MadGraphControl.MadGraphSystematicsUtils.SYSTEMATICS_WEIGHT_INFO%{'mur':1.0,'muf':1.0,'pdf':pdf+1}]
1252 if 'alternative_pdfs' in syst_setting and isinstance(syst_setting['alternative_pdfs'],list):
1253 for pdf in syst_setting['alternative_pdfs']:
1254 names+=[MadGraphControl.MadGraphSystematicsUtils.SYSTEMATICS_WEIGHT_INFO%{'mur':1.0,'muf':1.0,'pdf':pdf}]
1255 if 'scale_variations' in syst_setting and isinstance(syst_setting['scale_variations'],list):
1256 for mur in syst_setting['scale_variations']:
1257 for muf in syst_setting['scale_variations']:
1258 names+=[MadGraphControl.MadGraphSystematicsUtils.SYSTEMATICS_WEIGHT_INFO%{'mur':mur,'muf':muf,'pdf':syst_setting['central_pdf']}]
1259 return names
1260
1261def setup_bias_module(bias_module,process_dir):
1262 run_card = process_dir+'/Cards/run_card.dat'
1263 if isinstance(bias_module,tuple):
1264 mglog.info('Using bias module '+bias_module[0])
1265 the_run_card = open(run_card,'r')
1266 for line in the_run_card:
1267 if 'bias_module' in line and not bias_module[0] in line:
1268 raise RuntimeError('You need to add the bias module '+bias_module[0]+' to the run card to actually run it')
1269 the_run_card.close()
1270 if len(bias_module)!=3:
1271 raise RuntimeError('Please give a 3-tuple of strings containing bias module name, bias module, and makefile. Alternatively, give path to bias module tarball.')
1272 bias_module_newpath=process_dir+'/Source/BIAS/'+bias_module[0]
1273 os.makedirs(bias_module_newpath)
1274 bias_module_file=open(bias_module_newpath+'/'+bias_module[0]+'.f','w')
1275 bias_module_file.write(bias_module[1])
1276 bias_module_file.close()
1277 bias_module_make_file=open(bias_module_newpath+'/Makefile','w')
1278 bias_module_make_file.write(bias_module[2])
1279 bias_module_make_file.close()
1280 else:
1281 mglog.info('Using bias module '+bias_module)
1282 bias_module_name=bias_module.split('/')[-1].replace('.gz','')
1283 bias_module_name=bias_module_name.replace('.tar','')
1284 the_run_card = open(run_card,'r')
1285 for line in the_run_card:
1286 if 'bias_module' in line and bias_module_name not in line:
1287 raise RuntimeError('You need to add the bias module '+bias_module_name+' to the run card to actually run it')
1288 the_run_card.close()
1289
1290 if os.path.exists(bias_module+'.tar.gz'):
1291 bias_module_path=bias_module+'.tar.gz'
1292 elif os.path.exists(bias_module+'.gz'):
1293 bias_module_path=bias_module+'.gz'
1294 elif os.path.exists(bias_module):
1295 bias_module_path=bias_module
1296 else:
1297 mglog.error('Did not find bias module '+bias_module+' , this path should point to folder or tarball. Alternatively give a tuple of strings containing module name, module, and makefile')
1298 return 1
1299 bias_module_newpath=process_dir+'/Source/BIAS/'+bias_module_path.split('/')[-1]
1300 mglog.info('Copying bias module into place: '+bias_module_newpath)
1301 shutil.copy(bias_module_path,bias_module_newpath)
1302 mglog.info('Unpacking bias module')
1303 if bias_module_newpath.endswith('.tar.gz'):
1304 untar = stack_subprocess(['tar','xvzf',bias_module_newpath,'--directory='+process_dir+'/Source/BIAS/'])
1305 untar.wait()
1306 elif bias_module_path.endswith('.gz'):
1307 gunzip = stack_subprocess(['gunzip',bias_module_newpath])
1308 gunzip.wait()
1309
1310
1311def get_reweight_card(process_dir=MADGRAPH_GRIDPACK_LOCATION):
1312 if os.access(process_dir+'/Cards/reweight_card.dat',os.R_OK):
1313 return process_dir+'/Cards/reweight_card.dat'
1314 return None
1315
1316
1317def check_reweight_card(process_dir=MADGRAPH_GRIDPACK_LOCATION):
1318 reweight_card=get_reweight_card(process_dir=process_dir)
1319 shutil.move(reweight_card,reweight_card+'.old')
1320 oldcard = open(reweight_card+'.old','r')
1321 newcard = open(reweight_card,'w')
1322 changed = False
1323 info_expression=r'launch.*--rwgt_info\s*=\s*(\S+).*'
1324 name_expression=info_expression.replace('info','name')
1325 goodname_expression=r'^[A-Za-z0-9_\-.]+$'
1326 for line in oldcard:
1327 # we are only interested in the 'launch' line
1328 if not line.strip().startswith('launch') :
1329 newcard.write(line)
1330 else:
1331 rwgt_name_match=re.match(name_expression,line.strip())
1332 rwgt_info_match=re.match(info_expression,line.strip())
1333 if rwgt_name_match is None and rwgt_info_match is None:
1334 raise RuntimeError('Every reweighting should have a --rwgt_info (see https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/Reweight), please update your reweight_card accordingly. Line to fix: '+line)
1335 for match in [rwgt_info_match,rwgt_name_match]:
1336 if match is None:
1337 continue
1338 if len(match.groups())!=1:
1339 raise RuntimeError('Unexpected format of reweight card in line: '+line)
1340 if not re.match(goodname_expression,match.group(1)):
1341 raise RuntimeError('No special character in reweighting info/name, only allowing '+goodname_expression)
1342 if rwgt_info_match is not None:
1343 newcard.write(line)
1344 elif rwgt_name_match is not None:
1345 newcard.write(line.strip()+' --rwgt_info={0}\n'.format(rwgt_name_match.group(1)))
1346 changed=True
1347 if changed:
1348 mglog.info('Updated reweight_card')
1349 newcard.close()
1350 oldcard.close()
1351
1352
1353def update_lhe_file(lhe_file_old,param_card_old=None,lhe_file_new=None,masses={},delete_old_lhe=True):
1354 """Build a new LHE file from an old one and an updated param card.
1355 The masses of some particles can be changed via the masses dictionary. No particles that appear in the events
1356 may have their masses changed.
1357 If the param card is provided, the decay block in the LHE file will be replaced with the one in the param card.
1358 By default, the old LHE file is removed.
1359 If None is provided as a new LHE file name, the new file will replace the old one."""
1360 # If we want to just use a temp file, then put in a little temp holder
1361 lhe_file_new_tmp = lhe_file_new if lhe_file_new is not None else lhe_file_old+'.tmp'
1362 # Make sure the LHE file is there
1363 if not os.access(lhe_file_old,os.R_OK):
1364 raise RuntimeError('Could not access old LHE file at '+str(lhe_file_old)+'. Please check the file location.')
1365 # Grab the old param card
1366 if param_card_old is not None:
1367 paramcard = subprocess.Popen(['get_files','-data',param_card_old])
1368 paramcard.wait()
1369 if not os.access(param_card_old,os.R_OK):
1370 raise RuntimeError('Could not get param card '+param_card_old)
1371 # Don't overwrite old param cards
1372 if os.access(lhe_file_new_tmp,os.R_OK):
1373 raise RuntimeError('Old file at'+str(lhe_file_new_tmp)+' in the current directory. Dont want to clobber it. Please move it first.')
1374
1375 newlhe = open(lhe_file_new_tmp,'w')
1376 blockName = None
1377 decayEdit = False
1378 eventRead = False
1379 particles_in_events = []
1380 # Decay block ends with </slha>
1381
1382 with open(lhe_file_old,'r') as fileobject:
1383 for line in fileobject:
1384 if decayEdit and '</slha>' not in line:
1385 continue
1386 if decayEdit and '</slha>' in line:
1387 decayEdit = False
1388 if line.strip().upper().startswith('BLOCK') or line.strip().upper().startswith('DECAY')\
1389 and len(line.strip().split()) > 1:
1390 pos = 0 if line.strip().startswith('DECAY') else 1
1391 blockName = line.strip().upper().split()[pos]
1392
1393 akey = None
1394 if blockName != 'DECAY' and len(line.strip().split()) > 0:
1395 akey = line.strip().split()[0]
1396 elif blockName == 'DECAY' and len(line.strip().split()) > 1:
1397 akey = line.strip().split()[1]
1398
1399 # Replace the masses with those in the dictionary
1400 if akey is not None and blockName == 'MASS' and akey in masses:
1401 newlhe.write(' '+akey+' '+str(masses[akey])+' # \n')
1402 mglog.info(' '+akey+' '+str(masses[akey])+' #')
1403 decayEdit = False
1404 continue
1405
1406 # Replace the entire decay section of the LHE file with the one from the param card
1407 if blockName == 'DECAY' and param_card_old is not None:
1408 # We are now reading the decay blocks! Take them from the param card
1409 oldparam = open(param_card_old,'r')
1410 newDecays = False
1411 for old_line in oldparam.readlines():
1412 newBlockName = None
1413 if old_line.strip().upper().startswith('DECAY') and len(old_line.strip().split()) > 1:
1414 newBlockName = line.strip().upper().split()[pos]
1415 if newDecays:
1416 newlhe.write(old_line)
1417 elif newBlockName == 'DECAY':
1418 newDecays = True
1419 newlhe.write(old_line)
1420 oldparam.close()
1421 # Done adding the decays
1422 decayEdit = True
1423 blockName = None
1424 continue
1425
1426 # Keep a record of the particles that are in the events
1427 if not eventRead and '<event>' in line:
1428 eventRead = True
1429 if eventRead:
1430 if len(line.split())==11:
1431 aparticle = line.split()[0]
1432 if aparticle not in particles_in_events:
1433 particles_in_events += [aparticle]
1434
1435 # Otherwise write the line again
1436 newlhe.write(line)
1437
1438 # Check that none of the particles that we were setting the masses of appear in the LHE events
1439 for akey in masses:
1440 if akey in particles_in_events:
1441 mglog.error('Attempted to change mass of a particle that was in an LHE event! This is not allowed!')
1442 return -1
1443
1444 # Close up and return
1445 newlhe.close()
1446
1447 # Move the new file to the old file location
1448 if lhe_file_new is None:
1449 os.remove(lhe_file_old)
1450 shutil.move(lhe_file_new_tmp,lhe_file_old)
1451 lhe_file_new_tmp = lhe_file_old
1452 # Delete the old file if requested
1453 elif delete_old_lhe:
1454 os.remove(lhe_file_old)
1455
1456 return lhe_file_new_tmp
1457
1458
1459
1460def print_cards_from_dir(process_dir=MADGRAPH_GRIDPACK_LOCATION):
1461 card_dir=process_dir+'/Cards/'
1462 print_cards(proc_card=card_dir+'proc_card_mg5.dat',run_card=card_dir+'run_card.dat',param_card=card_dir+'param_card.dat',\
1463 madspin_card=card_dir+'madspin_card.dat',reweight_card=card_dir+'reweight_card.dat',warn_on_missing=False)
1464
1465
1466def print_cards(proc_card='proc_card_mg5.dat',run_card=None,param_card=None,madspin_card=None,reweight_card=None,warn_on_missing=True):
1467 if os.access(proc_card,os.R_OK):
1468 mglog.info("proc_card:")
1469 procCard = subprocess.Popen(['cat',proc_card])
1470 procCard.wait()
1471 elif warn_on_missing:
1472 mglog.warning('No proc_card: '+proc_card+' found')
1473
1474 if run_card is not None and os.access(run_card,os.R_OK):
1475 mglog.info("run_card:")
1476 runCard = subprocess.Popen(['cat',run_card])
1477 runCard.wait()
1478 elif run_card is not None and warn_on_missing:
1479 mglog.warning('No run_card: '+run_card+' found')
1480 else:
1481 mglog.info('Default run card in use')
1482
1483 if param_card is not None and os.access(param_card,os.R_OK):
1484 mglog.info("param_card:")
1485 paramCard = subprocess.Popen(['cat',param_card])
1486 paramCard.wait()
1487 elif param_card is not None and warn_on_missing:
1488 mglog.warning('No param_card: '+param_card+' found')
1489 else:
1490 mglog.info('Default param card in use')
1491
1492 if madspin_card is not None and os.access(madspin_card,os.R_OK):
1493 mglog.info("madspin_card:")
1494 madspinCard = subprocess.Popen(['cat',madspin_card])
1495 madspinCard.wait()
1496 elif madspin_card is not None and warn_on_missing:
1497 mglog.warning('No madspin_card: '+madspin_card+' found')
1498 else:
1499 mglog.info('No madspin card in use')
1500
1501 if reweight_card is not None and os.access(reweight_card,os.R_OK):
1502 mglog.info("reweight_card:")
1503 madspinCard = subprocess.Popen(['cat',reweight_card])
1504 madspinCard.wait()
1505 elif reweight_card is not None and warn_on_missing:
1506 mglog.warning('No reweight_card: '+reweight_card+' found')
1507 else:
1508 mglog.info('No reweight card in use')
1509
1510
1512 """ Simple function for checking if there is a grid pack.
1513 Relies on the specific location of the unpacked gridpack (madevent)
1514 which is here set as a global variable. The gridpack is untarred by
1515 the transform (Gen_tf.py) and no sign is sent to the job itself
1516 that there is a gridpack in use except the file's existence"""
1517 if os.access(MADGRAPH_GRIDPACK_LOCATION,os.R_OK):
1518 mglog.info('Located input grid pack area')
1519 return True
1520 return False
1521
1522
1523
1524def modify_run_card(run_card_input=None,run_card_backup=None,process_dir=MADGRAPH_GRIDPACK_LOCATION,runArgs=None,settings={},skipBaseFragment=False):
1525 """Build a new run_card.dat from an existing one.
1526 This function can get a fresh runcard from DATAPATH or start from the process directory.
1527 Settings is a dictionary of keys (no spaces needed) and values to replace.
1528 """
1529
1530 global my_MGC_instance # noqa: F824
1531 # my_MGC_instance.getRunCardDict(card_loc=process_dir+'/Cards/run_card.dat')
1532 my_MGC_instance.runCardDict.update(settings)
1533 # my_MGC_instance.write_runCard()
1534
1535 # Operate on lower case settings, and choose the capitalization MG5 has as the default (or all lower case)
1536 settings_lower = {}
1537 for s in list(settings.keys()):
1538 settings_lower[s.lower()] = settings[s]
1539
1540 # Check for the default run card location
1541 if run_card_input is None:
1542 run_card_input=get_default_runcard(process_dir)
1543 elif run_card_input is not None and not os.access(run_card_input,os.R_OK):
1544 runcard = subprocess.Popen(['get_files','-data',run_card_input])
1545 runcard.wait()
1546 if not os.access(run_card_input,os.R_OK):
1547 raise RuntimeError('Could not get run card '+run_card_input)
1548
1549 # guess NLO
1550 isNLO = my_MGC_instance.isNLO
1551 # add gobal PDF and scale uncertainty config to extras, except PDF or weights for syscal config are explictly set
1552 if not skipBaseFragment:
1553 setup_pdf_and_systematic_weights(MADGRAPH_PDFSETTING,settings_lower,isNLO)
1554
1555 # Get some info out of the runArgs
1556 if runArgs is not None:
1557 beamEnergy,rand_seed = get_runArgs_info(runArgs)
1558 if 'iseed' not in settings_lower:
1559 settings_lower['iseed']=rand_seed
1560 if not isNLO and 'python_seed' not in settings_lower:
1561 settings_lower['python_seed']=rand_seed
1562 if 'beamenergy' in settings_lower:
1563 mglog.warning('Do not set beam energy in MG settings. The variables are ebeam1 and ebeam2. Will use your setting of '+str(settings_lower['beamenergy']))
1564 beamEnergy=settings_lower['beamenergy']
1565 settings_lower.pop('beamenergy')
1566 if 'ebeam1' not in settings_lower:
1567 settings_lower['ebeam1']=beamEnergy
1568 if 'ebeam2' not in settings_lower:
1569 settings_lower['ebeam2']=beamEnergy
1570 # Make sure nevents is an integer
1571 if 'nevents' in settings_lower:
1572 settings_lower['nevents'] = int(settings_lower['nevents'])
1573
1574 # Normalise custom_fcts early so the rewritten run_card uses the full path
1575 if 'custom_fcts' in settings_lower and settings_lower['custom_fcts']:
1576 raw_name = str(settings_lower['custom_fcts']).split()[0]
1577 # Determine jobConfig directory
1578 if runArgs is not None and hasattr(runArgs, 'jobConfig'):
1579 cfgdir = runArgs.jobConfig[0] if isinstance(runArgs.jobConfig, (list, tuple)) else runArgs.jobConfig
1580 # Build full path and make absolute
1581 full_path = os.path.join(cfgdir, raw_name)
1582 settings_lower['custom_fcts'] = os.path.abspath(full_path)
1583 print(f"Using custom function(s), specified in custom_fcts with path: {settings_lower['custom_fcts']}")
1584 else:
1585 # For internal tests, where jobConfig is not set
1586 settings_lower['custom_fcts'] = os.path.abspath(raw_name)
1587
1588 mglog.info('Modifying run card located at '+run_card_input)
1589 if run_card_backup is not None:
1590 mglog.info('Keeping backup of original run card at '+run_card_backup)
1591 run_card_old = run_card_backup
1592 else:
1593 run_card_old = run_card_input+'.old_to_be_deleted'
1594 mglog.debug('Modifying runcard settings: '+str(settings_lower))
1595 if os.path.isfile(run_card_old):
1596 os.unlink(run_card_old) # delete old backup
1597 os.rename(run_card_input, run_card_old) # change name of original card
1598
1599 oldCard = open(run_card_old, 'r')
1600 newCard = open(process_dir+'/Cards/run_card.dat', 'w')
1601 used_settings = []
1602 for line in iter(oldCard):
1603 if not line.strip().startswith('#'): # line commented out
1604 command = line.split('!', 1)[0]
1605 comment = line.split('!', 1)[1] if '!' in line else ''
1606 if '=' in command:
1607 setting = command.split('=')[-1] #.strip()
1608 stripped_setting = setting.strip()
1609 oldValue = '='.join(command.split('=')[:-1])
1610 if stripped_setting.lower() in settings_lower:
1611 # if setting set to 'None' it will be removed from run_card
1612 if settings_lower[stripped_setting.lower()] is None:
1613 line=''
1614 mglog.info('Removing '+stripped_setting+'.')
1615 used_settings += [ stripped_setting.lower() ]
1616 else:
1617 if stripped_setting.lower() == 'custom_fcts':
1618 # Overwrite completely to avoid duplicating in custom_fcts, else MadGraph will crash
1619 line = ' '+str(settings_lower[stripped_setting.lower()])+' = '+setting
1620 if comment != '':
1621 line += ' !'+comment
1622 else:
1623 line = oldValue.replace(oldValue.strip(), str(settings_lower[stripped_setting.lower()]))+'='+setting
1624 if comment != '':
1625 line += ' !' + comment
1626 mglog.info('Setting '+stripped_setting+' = '+str(settings_lower[stripped_setting.lower()]))
1627 used_settings += [ stripped_setting.lower() ]
1628 newCard.write(line.strip()+'\n')
1629
1630 # Check whether mcatnlo_delta is applied to setup pythia8 path
1631 if 'mcatnlo_delta' in settings_lower:
1632 if settings_lower['mcatnlo_delta'] == 'True':
1633 modify_config_card(process_dir=process_dir,settings={'pythia8_path':os.getenv("PY8PATH")})
1634
1635
1636 # Clean up unused options
1637 for asetting in settings_lower:
1638 if asetting in used_settings:
1639 continue
1640 if settings_lower[asetting] is None:
1641 continue
1642 mglog.info('Option '+asetting+' was not in the default run_card (normal for hidden options). Adding by hand a setting to '+str(settings_lower[asetting]) )
1643 newCard.write( ' '+str(settings_lower[asetting])+' = '+str(asetting)+'\n')
1644 # close files
1645 oldCard.close()
1646 newCard.close()
1647 mglog.info('Finished modification of run card.')
1648 if run_card_backup is None:
1649 os.unlink(run_card_old)
1650
1651
1652def modify_config_card(config_card_backup=None,process_dir=MADGRAPH_GRIDPACK_LOCATION,settings={},set_commented=True):
1653 """Build a new configuration from an existing one.
1654 This function can get a fresh runcard from DATAPATH or start from the process directory.
1655 Settings is a dictionary of keys (no spaces needed) and values to replace.
1656 """
1657 global my_MGC_instance # noqa: F824
1658
1659 my_MGC_instance.configCardDict.update(settings)
1660 # Check for the default config card location
1661 config_card = my_MGC_instance.config_path
1662
1663 # The format is similar to the run card, but backwards
1664 mglog.info('Modifying config card located at '+config_card)
1665 if config_card_backup is not None:
1666 mglog.info('Keeping backup of original config card at '+config_card_backup)
1667 config_card_old = config_card_backup
1668 else:
1669 config_card_old = config_card+'.old_to_be_deleted'
1670 mglog.debug('Modifying config card settings: '+str(settings))
1671 if os.path.isfile(config_card_old):
1672 os.unlink(config_card_old) # delete old backup
1673 os.rename(config_card, config_card_old) # change name of original card
1674
1675 oldCard = open(config_card_old, 'r')
1676 newCard = open(config_card, 'w')
1677 used_settings = []
1678 for line in iter(oldCard):
1679 lmod = line if set_commented else line.split('#')[0]
1680 if '=' in lmod:
1681 modified = False
1682 for setting in settings:
1683 if setting not in lmod:
1684 continue
1685 # Assume we hit
1686 mglog.info('Setting '+setting.strip()+' to '+str(settings[setting]))
1687 newCard.write(' '+str(setting.strip())+' = '+str(settings[setting])+'\n')
1688 used_settings += [ setting.strip() ]
1689 modified = True
1690 break
1691 if modified:
1692 continue
1693 newCard.write(line)
1694
1695 # Clean up unused options
1696 for asetting in settings:
1697 if asetting in used_settings:
1698 continue
1699 if settings[asetting] is None:
1700 continue
1701 mglog.warning('Option '+asetting+' was not in the default config card. Adding by hand a setting to '+str(settings[asetting]) )
1702 newCard.write(' '+str(asetting)+' = '+str(settings[asetting])+'\n')
1703 # close files
1704 oldCard.close()
1705 newCard.close()
1706 mglog.info('Finished modification of config card.')
1707 if config_card_backup is None:
1708 os.unlink(config_card_old)
1709
1710
1711
1713 global my_MGC_instance # noqa: F824
1714 if 'cluster_type' in my_MGC_instance.configCardDict:
1715 return my_MGC_instance.configCardDict['cluster_type']
1716 else:
1717 return None
1718
1719
1720
1721
1722def add_reweighting(run_name,reweight_card=None,process_dir=MADGRAPH_GRIDPACK_LOCATION):
1723 mglog.info('Running reweighting module on existing events')
1724 if reweight_card is not None:
1725 mglog.info('Copying new reweight card from '+reweight_card)
1726 shutil.move(reweight_card,process_dir+'/Cards/reweight_card.dat')
1727 reweight_cmd='{}/bin/madevent reweight {} -f'.format(process_dir,run_name)
1728 reweight = stack_subprocess([python]+reweight_cmd.split(),stdin=subprocess.PIPE,stderr=subprocess.PIPE if MADGRAPH_CATCH_ERRORS else None)
1729 (out,err) = reweight.communicate()
1730 error_check(err,reweight.returncode)
1731 mglog.info('Finished reweighting')
1732
1733
1734
1735
1736def ls_dir(directory):
1737 mglog.info('For your information, ls of '+directory+':')
1738 mglog.info( sorted( os.listdir( directory ) ) )
1739
1740# Final import of some code used in these functions
1741import MadGraphControl.MadGraphSystematicsUtils
1742
1743# To be removed once we moved past MG5 3.3.1
1744def fix_fks_makefile(process_dir):
1745 makefile_fks=process_dir+'/SubProcesses/makefile_fks_dir'
1746 mglog.info('Fixing '+makefile_fks)
1747 shutil.move(makefile_fks,makefile_fks+'_orig')
1748 fin=open(makefile_fks+'_orig')
1749 fout=open(makefile_fks,'w')
1750 edit=False
1751 for line in fin:
1752 if 'FKSParams.mod' in line:
1753 fout.write(line.replace('FKSParams.mod','FKSParams.o'))
1754 edit=True
1755 elif edit and 'driver_mintFO' in line:
1756 fout.write('driver_mintFO.o: weight_lines.o mint_module.o FKSParams.o\n')
1757 elif edit and 'genps_fks.o' in line:
1758 fout.write('genps_fks.o: mint_module.o FKSParams.o\n')
1759 elif edit and 'test_soft_col_limits' in line:
1760 fout.write(line)
1761 fout.write('madfks_plot.o: mint_module.o\n')
1762 fout.write('cluster.o: weight_lines.o\n')
1763 else:
1764 fout.write(line)
1765 fin.close()
1766 fout.close()
1767
1768#==================================================================================
1769# this function is called during build_run card to check the consistency of user-provided arguments with the inlude
1770# and throw errors, warnings, or corrects the input as is appropriate
1771def setup_pdf_and_systematic_weights(the_base_fragment,extras,isNLO):
1772
1773 global my_MGC_instance # noqa: F824
1774
1775
1776 list = []
1777 tmp_dict = {}
1778 for k in extras:
1779 k_clean=k.lower().replace("'",'').replace('"','')
1780 if k_clean!=k and k_clean in systematics_run_card_options(isNLO):
1781 list.append(k)
1782 tmp_dict[k_clean] = extras[k]
1783 # Removing systematics with incorrect formatting
1784 for o in list:
1785 if o in extras:
1786 extras.pop(o,None)
1787 # Adding cleaned up systematics into dictionary
1788 extras.update(tmp_dict)
1789
1790 if my_MGC_instance.base_fragment_setup_check(the_base_fragment,extras,isNLO):
1791 return
1792 # if something is set that contradicts the base fragment: bad!
1793 for o in systematics_run_card_options(isNLO):
1794 if o in extras:
1795 mglog.warning('You tried to set "'+str(o)+'" by hand, but you should trust the base fragment with the following options: '+', '.join(systematics_run_card_options(isNLO)))
1796 mglog.info('We will update "'+str(o))
1797
1798 new_settings=get_pdf_and_systematic_settings(the_base_fragment,isNLO)
1799
1800 user_set_extras=dict(extras)
1801 for s in new_settings:
1802 if s is not None:
1803 extras[s]=new_settings[s]
1804
1805
1806 mglog.info('PDF and scale settings were set as follows:')
1807 for p in systematics_run_card_options(isNLO):
1808 user_set='not set'
1809 if p in user_set_extras:
1810 user_set=str(user_set_extras[p])
1811 new_value='not set'
1812 if p in extras:
1813 new_value=str(extras[p])
1814 mglog.info('MadGraphUtils set '+str(p)+' to "'+new_value+'", was set to "'+user_set+'"')
int upper(int c)
void print(char *figname, TCanvas *c1)
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
get_default_runcard(process_dir=MADGRAPH_GRIDPACK_LOCATION)
madspin_on_lhe(input_LHE, madspin_card, runArgs=None, keep_original=False)
print_cards_from_dir(process_dir=MADGRAPH_GRIDPACK_LOCATION)
generate_prep(process_dir)
get_reweight_card(process_dir=MADGRAPH_GRIDPACK_LOCATION)
add_lifetimes(process_dir, threshold=None)
add_reweighting(run_name, reweight_card=None, process_dir=MADGRAPH_GRIDPACK_LOCATION)
modify_config_card(config_card_backup=None, process_dir=MADGRAPH_GRIDPACK_LOCATION, settings={}, set_commented=True)
get_expected_systematic_names(syst_setting)
get_expected_reweight_names(reweight_card_loc)
setup_bias_module(bias_module, process_dir)
stack_subprocess(command, **kwargs)
arrange_output(process_dir=MADGRAPH_GRIDPACK_LOCATION, lhe_version=None, saveProcDir=False, runArgs=None, fixEventWeightsForBridgeMode=False)
generate_from_gridpack(runArgs=None, extlhapath=None, gridpack_compile=None, requirePMGSettings=False)
modify_run_card(run_card_input=None, run_card_backup=None, process_dir=MADGRAPH_GRIDPACK_LOCATION, runArgs=None, settings={}, skipBaseFragment=False)
update_lhe_file(lhe_file_old, param_card_old=None, lhe_file_new=None, masses={}, delete_old_lhe=True)
setup_pdf_and_systematic_weights(the_base_fragment, extras, isNLO)
check_reweight_card(process_dir=MADGRAPH_GRIDPACK_LOCATION)
setNCores(process_dir, Ncores=None)
print_cards(proc_card='proc_card_mg5.dat', run_card=None, param_card=None, madspin_card=None, reweight_card=None, warn_on_missing=True)
setupFastjet(process_dir=None)
add_madspin(madspin_card=None, process_dir=MADGRAPH_GRIDPACK_LOCATION)
new_process(process='generate p p > t t~\noutput -f', plugin=None, keepJpegs=False, usePMGSettings=False)
setupLHAPDF(process_dir=None, extlhapath=None, allow_links=True)
fix_fks_makefile(process_dir)