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