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