1
################################################################################
3
# Copyright (c) 2011 The MadGraph Development team and Contributors
5
# This file is a part of the MadGraph 5 project, an application which
6
# automatically generates Feynman diagrams and matrix elements for arbitrary
7
# high-energy processes in the Standard Model and beyond.
9
# It is subject to the MadGraph license which should accompany this
12
# For more information, please visit: http://madgraph.phys.ucl.ac.be
14
################################################################################
15
"""A user friendly command line interface to access MadGraph features.
16
Uses the cmd package for command interpretation and tab completion.
18
from __future__ import division
40
GNU_SPLITTING = ('GNU' in readline.__doc__)
44
root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
45
root_path = os.path.split(root_path)[0]
46
sys.path.insert(0, os.path.join(root_path,'bin'))
50
# Special logger for the Cmd Interface
51
logger = logging.getLogger('madevent.stdout') # -> stdout
52
logger_stderr = logging.getLogger('madevent.stderr') # ->stderr
55
# import from madgraph directory
56
import madgraph.interface.extended_cmd as cmd
57
import madgraph.interface.common_run_interface as common_run
58
import madgraph.iolibs.files as files
59
import madgraph.iolibs.save_load_object as save_load_object
60
import madgraph.various.banner as banner_mod
61
import madgraph.various.cluster as cluster
62
import madgraph.various.gen_crossxhtml as gen_crossxhtml
63
import madgraph.various.sum_html as sum_html
64
import madgraph.various.misc as misc
65
import madgraph.various.combine_runs as combine_runs
67
import models.check_param_card as check_param_card
68
from madgraph import InvalidCmd, MadGraph5Error, MG5DIR
70
except ImportError, error:
73
# import from madevent directory
74
import internal.extended_cmd as cmd
75
import internal.common_run_interface as common_run
76
import internal.banner as banner_mod
77
import internal.misc as misc
78
from internal import InvalidCmd, MadGraph5Error
79
import internal.files as files
80
import internal.gen_crossxhtml as gen_crossxhtml
81
import internal.save_load_object as save_load_object
82
import internal.cluster as cluster
83
import internal.check_param_card as check_param_card
84
import internal.sum_html as sum_html
85
import internal.combine_runs as combine_runs
88
class MadEventError(Exception):
91
class ZeroResult(MadEventError):
94
#===============================================================================
96
#===============================================================================
97
class CmdExtended(common_run.CommonRunCmd):
98
"""Particularisation of the cmd command for MadEvent"""
100
#suggested list of command
105
debug_output = 'ME5_debug'
106
error_debug = 'Please report this bug on https://bugs.launchpad.net/madgraph5\n'
107
error_debug += 'More information is found in \'%(debug)s\'.\n'
108
error_debug += 'Please attach this file to your report.'
110
config_debug = 'If you need help with this issue please contact us on https://answers.launchpad.net/madgraph5\n'
113
keyboard_stop_msg = """stopping all operation
114
in order to quit madevent please enter exit"""
117
InvalidCmd = InvalidCmd
118
ConfigurationError = MadGraph5Error
120
def __init__(self, me_dir, options, *arg, **opt):
121
"""Init history and line continuation"""
123
# Tag allowing/forbiding question
126
# If possible, build an info line with current version number
127
# and date, from the VERSION text file
128
info = misc.get_pkg_info()
130
if info and info.has_key('version') and info.has_key('date'):
131
len_version = len(info['version'])
132
len_date = len(info['date'])
133
if len_version + len_date < 30:
134
info_line = "#* VERSION %s %s %s *\n" % \
136
(30 - len_version - len_date) * ' ',
139
version = open(pjoin(root_path,'MGMEVersion.txt')).readline().strip()
140
info_line = "#* VERSION %s %s *\n" % \
141
(version, (24 - len(version)) * ' ')
143
# Create a header for the history file.
144
# Remember to fill in time at writeout time!
145
self.history_header = \
146
'#************************************************************\n' + \
147
'#* MadGraph/MadEvent 5 *\n' + \
151
"#* * * * * 5 * * * * *\n" + \
158
"#* The MadGraph Development Team - Please visit us at *\n" + \
159
"#* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
161
'#************************************************************\n' + \
163
'#* Command File for MadEvent *\n' + \
165
'#* run as ./bin/madevent.py filename *\n' + \
167
'#************************************************************\n'
170
info_line = info_line[1:]
173
"************************************************************\n" + \
175
"* W E L C O M E to M A D G R A P H 5 *\n" + \
176
"* M A D E V E N T *\n" + \
180
"* * * * * 5 * * * * *\n" + \
186
"* The MadGraph Development Team - Please visit us at *\n" + \
187
"* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
189
"* Type 'help' for in-line help. *\n" + \
191
"************************************************************")
192
super(CmdExtended, self).__init__(me_dir, options, *arg, **opt)
194
def get_history_header(self):
195
"""return the history header"""
196
return self.history_header % misc.get_time_info()
198
def stop_on_keyboard_stop(self):
199
"""action to perform to close nicely on a keyboard interupt"""
201
if hasattr(self, 'cluster'):
202
logger.info('rm jobs on queue')
203
self.cluster.remove()
204
if hasattr(self, 'results'):
205
self.update_status('Stop by the user', level=None, makehtml=False, error=True)
206
self.add_error_log_in_html(KeyboardInterrupt)
210
def postcmd(self, stop, line):
211
""" Update the status of the run for finishing interactive command """
213
stop = super(CmdExtended, self).postcmd(stop, line)
214
# relaxing the tag forbidding question
217
if not self.use_rawinput:
220
if self.results and not self.results.current:
226
if isinstance(self.results.status, str) and self.results.status.startswith('Error'):
228
if isinstance(self.results.status, str) and self.results.status == 'Stop by the user':
229
self.update_status('%s Stop by the user' % arg[0], level=None, error=True)
231
elif not self.results.status:
233
elif str(arg[0]) in ['exit','quit','EOF']:
237
self.update_status('Command \'%s\' done.<br> Waiting for instruction.' % arg[0],
238
level=None, error=True)
240
misc.sprint('update_status fails')
244
def nice_user_error(self, error, line):
245
"""If a ME run is currently running add a link in the html output"""
247
self.add_error_log_in_html()
248
cmd.Cmd.nice_user_error(self, error, line)
250
def nice_config_error(self, error, line):
251
"""If a ME run is currently running add a link in the html output"""
253
self.add_error_log_in_html()
254
cmd.Cmd.nice_config_error(self, error, line)
258
debug_file = open(self.debug_output, 'a')
259
debug_file.write(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')))
265
def nice_error_handling(self, error, line):
266
"""If a ME run is currently running add a link in the html output"""
268
if isinstance(error, ZeroResult):
269
self.add_error_log_in_html(error)
270
logger.warning('Zero result detected: %s' % error)
271
# create a banner if needed
274
self.banner = banner_mod.Banner()
275
if 'slha' not in self.banner:
276
self.banner.add(pjoin(self.me_dir,'Cards','param_card.dat'))
277
if 'mgruncard' not in self.banner:
278
self.banner.add(pjoin(self.me_dir,'Cards','run_card.dat'))
279
if 'mg5proccard' not in self.banner:
280
proc_card = pjoin(self.me_dir,'Cards','proc_card_mg5.dat')
281
if os.path.exists(proc_card):
282
self.banner.add(proc_card)
284
out_dir = pjoin(self.me_dir, 'Events', self.run_name)
285
if not os.path.isdir(out_dir):
287
output_path = pjoin(out_dir, '%s_%s_banner.txt' % \
288
(self.run_name, self.run_tag))
289
self.banner.write(output_path)
296
self.add_error_log_in_html()
297
cmd.Cmd.nice_error_handling(self, error, line)
299
debug_file = open(self.debug_output, 'a')
300
debug_file.write(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')))
306
#===============================================================================
308
#===============================================================================
309
class HelpToCmd(object):
310
""" The Series of help routine for the MadEventCmd"""
312
def help_banner_run(self):
313
logger.info("syntax: banner_run Path|RUN [--run_options]")
314
logger.info("-- Reproduce a run following a given banner")
315
logger.info(" One of the following argument is require:")
316
logger.info(" Path should be the path of a valid banner.")
317
logger.info(" RUN should be the name of a run of the current directory")
318
self.run_options_help([('-f','answer all question by default'),
319
('--name=X', 'Define the name associated with the new run')])
322
logger.info("syntax: open FILE ")
323
logger.info("-- open a file with the appropriate editor.")
324
logger.info(' If FILE belongs to index.html, param_card.dat, run_card.dat')
325
logger.info(' the path to the last created/used directory is used')
326
logger.info(' The program used to open those files can be chosen in the')
327
logger.info(' configuration file ./input/mg5_configuration.txt')
330
def run_options_help(self, data):
332
logger.info('-- local options:')
333
for name, info in data:
334
logger.info(' %s : %s' % (name, info))
336
logger.info("-- session options:")
337
logger.info(" Note that those options will be kept for the current session")
338
logger.info(" --cluster : Submit to the cluster. Current cluster: %s" % self.options['cluster_type'])
339
logger.info(" --multicore : Run in multi-core configuration")
340
logger.info(" --nb_core=X : limit the number of core to use to X.")
343
def help_generate_events(self):
344
logger.info("syntax: generate_events [run_name] [options])")
345
logger.info("-- Launch the full chain of script for the generation of events")
346
logger.info(" Including possible plotting, shower and detector resolution.")
347
logger.info(" Those steps are performed if the related program are installed")
348
logger.info(" and if the related card are present in the Cards directory.")
349
self.run_options_help([('-f', 'Use default for all questions.'),
350
('--laststep=', 'argument might be parton/pythia/pgs/delphes and indicate the last level to be run.')])
353
def help_add_time_of_flight(self):
354
logger.info("syntax: add_time_of_flight [run_name|path_to_file] [--treshold=]")
355
logger.info('-- Add in the lhe files the information')
356
logger.info(' of how long it takes to a particle to decay.')
357
logger.info(' threshold option allows to change the minimal value required to')
358
logger.info(' a non zero value for the particle (default:1e-12s)')
360
def help_calculate_decay_widths(self):
362
if self.ninitial != 1:
363
logger.warning("This command is only valid for processes of type A > B C.")
364
logger.warning("This command can not be run in current context.")
367
logger.info("syntax: calculate_decay_widths [run_name] [options])")
368
logger.info("-- Calculate decay widths and enter widths and BRs in param_card")
369
logger.info(" for a series of processes of type A > B C ...")
370
self.run_options_help([('-f', 'Use default for all questions.'),
371
('--accuracy=', 'accuracy (for each partial decay width).'\
372
+ ' Default is 0.01.')])
374
def help_multi_run(self):
375
logger.info("syntax: multi_run NB_RUN [run_name] [--run_options])")
376
logger.info("-- Launch the full chain of script for the generation of events")
377
logger.info(" NB_RUN times. This chains includes possible plotting, shower")
378
logger.info(" and detector resolution.")
379
self.run_options_help([('-f', 'Use default for all questions.'),
380
('--laststep=', 'argument might be parton/pythia/pgs/delphes and indicate the last level to be run.')])
382
def help_survey(self):
383
logger.info("syntax: survey [run_name] [--run_options])")
384
logger.info("-- evaluate the different channel associate to the process")
385
self.run_options_help([("--" + key,value[-1]) for (key,value) in \
386
self._survey_options.items()])
388
def help_launch(self):
389
"""exec generate_events for 2>N and calculate_width for 1>N"""
390
logger.info("syntax: launch [run_name] [options])")
391
logger.info(" --alias for either generate_events/calculate_decay_widths")
392
logger.info(" depending of the number of particles in the initial state.")
394
if self.ninitial == 1:
395
logger.info("For this directory this is equivalent to calculate_decay_widths")
396
self.help_calculate_decay_widths()
398
logger.info("For this directory this is equivalent to $generate_events")
399
self.help_generate_events()
401
def help_refine(self):
402
logger.info("syntax: refine require_precision [max_channel] [--run_options]")
403
logger.info("-- refine the LAST run to achieve a given precision.")
404
logger.info(" require_precision: can be either the targeted number of events")
405
logger.info(' or the required relative error')
406
logger.info(' max_channel:[5] maximal number of channel per job')
407
self.run_options_help([])
409
def help_combine_events(self):
411
logger.info("syntax: combine_events [run_name] [--tag=tag_name] [--run_options]")
412
logger.info("-- Combine the last run in order to write the number of events")
413
logger.info(" asked in the run_card.")
414
self.run_options_help([])
416
def help_compute_widths(self):
417
logger.info("syntax: compute_widths Particle [Particles] [Param_card] [--output=PATH]")
418
logger.info("-- Compute the widths (ONLY 1->2) for the particles specified.")
419
logger.info(" By default, this takes the current param_card and overwrites it.")
421
def help_store_events(self):
423
logger.info("syntax: store_events [--run_options]")
424
logger.info("-- Write physically the events in the files.")
425
logger.info(" should be launch after \'combine_events\'")
426
self.run_options_help([])
428
def help_create_gridpack(self):
430
logger.info("syntax: create_gridpack [--run_options]")
431
logger.info("-- create the gridpack. ")
432
logger.info(" should be launch after \'store_events\'")
433
self.run_options_help([])
435
def help_import(self):
437
logger.info("syntax: import command PATH")
438
logger.info("-- Execute the command present in the file")
439
self.run_options_help([])
441
def help_remove(self):
442
logger.info("syntax: remove RUN [all|parton|pythia|pgs|delphes|banner] [-f] [--tag=]")
443
logger.info("-- Remove all the files linked to previous run RUN")
444
logger.info(" if RUN is 'all', then all run will be cleaned.")
445
logger.info(" The optional argument precise which part should be cleaned.")
446
logger.info(" By default we clean all the related files but the banners.")
447
logger.info(" the optional '-f' allows to by-pass all security question")
448
logger.info(" The banner can be remove only if all files are removed first.")
450
#===============================================================================
452
#===============================================================================
453
class CheckValidForCmd(object):
454
""" The Series of check routine for the MadEventCmd"""
456
def check_banner_run(self, args):
457
"""check the validity of line"""
460
self.help_banner_run()
461
raise self.InvalidCmd('banner_run reauires at least one argument.')
463
tag = [a[6:] for a in args if a.startswith('--tag=')]
466
if os.path.exists(args[0]):
468
format = self.detect_card_type(args[0])
469
if format != 'banner':
470
raise self.InvalidCmd('The file is not a valid banner.')
472
args[0] = pjoin(self.me_dir,'Events', args[0], '%s_%s_banner.txt' % \
474
if not os.path.exists(args[0]):
475
raise self.InvalidCmd('No banner associates to this name and tag.')
479
banners = glob.glob(pjoin(self.me_dir,'Events', args[0], '*_banner.txt'))
481
raise self.InvalidCmd('No banner associates to this name.')
482
elif len(banners) == 1:
485
#list the tag and propose those to the user
486
tags = [os.path.basename(p)[len(args[0])+1:-11] for p in banners]
487
tag = self.ask('which tag do you want to use?', tags[0], tags)
488
args[0] = pjoin(self.me_dir,'Events', args[0], '%s_%s_banner.txt' % \
491
run_name = [arg[7:] for arg in args if arg.startswith('--name=')]
494
self.exec_cmd('remove %s all banner -f' % run_name)
497
self.set_run_name(args[0], tag=None, level='parton', reload_card=True)
498
elif type == 'banner':
499
self.set_run_name(self.find_available_run_name(self.me_dir))
501
if not self.results[name].is_empty():
502
run_name = self.find_available_run_name(self.me_dir)
503
logger.info('Run %s is not empty so will use run_name: %s' % \
505
self.set_run_name(run_name)
508
self.exec_cmd('remove %s all banner -f' % run_name)
511
self.set_run_name(name)
513
def check_history(self, args):
514
"""check the validity of line"""
518
raise self.InvalidCmd('\"history\" command takes at most one argument')
522
elif args[0] != 'clean':
523
dirpath = os.path.dirname(args[0])
524
if dirpath and not os.path.exists(dirpath) or \
525
os.path.isdir(args[0]):
526
raise self.InvalidCmd("invalid path %s " % dirpath)
528
def check_save(self, args):
529
""" check the validity of the line"""
532
args.append('options')
534
if args[0] not in self._save_opts:
535
raise self.InvalidCmd('wrong \"save\" format')
537
if args[0] != 'options' and len(args) != 2:
539
raise self.InvalidCmd('wrong \"save\" format')
540
elif args[0] != 'options' and len(args) == 2:
541
basename = os.path.dirname(args[1])
542
if not os.path.exists(basename):
543
raise self.InvalidCmd('%s is not a valid path, please retry' % \
546
if args[0] == 'options':
549
if arg in ['--auto', '--all']:
551
elif arg.startswith('--'):
552
raise self.InvalidCmd('unknow command for \'save options\'')
554
basename = os.path.dirname(arg)
555
if not os.path.exists(basename):
556
raise self.InvalidCmd('%s is not a valid path, please retry' % \
559
raise self.InvalidCmd('only one path is allowed')
565
if '--auto' in arg and self.options['mg5_path']:
566
args.insert(1, pjoin(self.options['mg5_path'],'input','mg5_configuration.txt'))
568
args.insert(1, pjoin(self.me_dir,'Cards','me5_configuration.txt'))
571
def check_survey(self, args, cmd='survey'):
572
"""check that the argument for survey are valid"""
575
self.opts = dict([(key,value[1]) for (key,value) in \
576
self._survey_options.items()])
578
# Treat any arguments starting with '--'
579
while args and args[-1].startswith('--'):
582
for opt,value in self._survey_options.items():
583
if arg.startswith('--%s=' % opt):
584
exec('self.opts[\'%s\'] = %s(arg.split(\'=\')[-1])' % \
587
if arg != "": raise Exception
590
raise self.InvalidCmd('invalid %s argument'% arg)
594
raise self.InvalidCmd('Too many argument for %s command' % cmd)
596
# No run name assigned -> assigned one automaticaly
597
self.set_run_name(self.find_available_run_name(self.me_dir))
599
self.set_run_name(args[0], None,'parton', True)
604
def check_generate_events(self, args):
605
"""check that the argument for generate_events are valid"""
608
if args and args[-1].startswith('--laststep='):
609
run = args[-1].split('=')[-1]
610
if run not in ['auto','parton', 'pythia', 'pgs', 'delphes']:
611
self.help_generate_events()
612
raise self.InvalidCmd('invalid %s argument'% args[-1])
613
if run != 'parton' and not self.options['pythia-pgs_path']:
614
raise self.InvalidCmd('''pythia-pgs not install. Please install this package first.
615
To do so type: \'install pythia-pgs\' in the mg5 interface''')
616
if run == 'delphes' and not self.options['delphes_path']:
617
raise self.InvalidCmd('''delphes not install. Please install this package first.
618
To do so type: \'install Delphes\' in the mg5 interface''')
622
self.help_generate_events()
623
raise self.InvalidCmd('Too many argument for generate_events command: %s' % cmd)
627
def check_add_time_of_flight(self, args):
628
"""check that the argument are correct"""
632
self.help_time_of_flight()
633
raise self.InvalidCmd('Too many arguments')
635
# check if the threshold is define. and keep it's value
636
if args and args[-1].startswith('--threshold='):
638
threshold = float(args[-1].split('=')[1])
640
raise self.InvalidCmd('threshold options require a number.')
641
args.remove(args[-1])
645
if len(args) == 1 and os.path.exists(args[0]):
648
if len(args) and self.run_name != args[0]:
649
self.set_run_name(args.pop(0))
650
elif not self.run_name:
651
self.help_add_time_of_flight()
652
raise self.InvalidCmd('Need a run_name to process')
653
event_path = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')
654
if not os.path.exists(event_path):
655
event_path = event_path[:-3]
656
if not os.path.exists(event_path):
657
raise self.InvalidCmd('No unweighted events associate to this run.')
662
args[:] = [event_path, threshold]
664
def check_calculate_decay_widths(self, args):
665
"""check that the argument for calculate_decay_widths are valid"""
667
if self.ninitial != 1:
668
raise self.InvalidCmd('Can only calculate decay widths for decay processes A > B C ...')
672
if args and args[-1].startswith('--accuracy='):
674
accuracy = float(args[-1].split('=')[-1])
676
raise self.InvalidCmd('Argument error in calculate_decay_widths command')
679
self.help_calculate_decay_widths()
680
raise self.InvalidCmd('Too many argument for calculate_decay_widths command: %s' % cmd)
686
def check_multi_run(self, args):
687
"""check that the argument for survey are valid"""
692
self.help_multi_run()
693
raise self.InvalidCmd("""multi_run command requires at least one argument for
694
the number of times that it call generate_events command""")
696
if args[-1].startswith('--laststep='):
697
run = args[-1].split('=')[-1]
698
if run not in ['parton', 'pythia', 'pgs', 'delphes']:
699
self.help_multi_run()
700
raise self.InvalidCmd('invalid %s argument'% args[-1])
701
if run != 'parton' and not self.options['pythia-pgs_path']:
702
raise self.InvalidCmd('''pythia-pgs not install. Please install this package first.
703
To do so type: \'install pythia-pgs\' in the mg5 interface''')
704
if run == 'delphes' and not self.options['delphes_path']:
705
raise self.InvalidCmd('''delphes not install. Please install this package first.
706
To do so type: \'install Delphes\' in the mg5 interface''')
710
elif not args[0].isdigit():
711
self.help_multi_run()
712
raise self.InvalidCmd("The first argument of multi_run should be a integer.")
714
self.check_survey(args, cmd='multi_run')
715
args.insert(0, int(nb_run))
719
def check_refine(self, args):
720
"""check that the argument for survey are valid"""
722
# if last argument is not a number -> it's the run_name (Not allow anymore)
727
raise self.InvalidCmd('Not valid arguments')
730
raise self.InvalidCmd('require_precision argument is require for refine cmd')
733
if not self.run_name:
734
if self.results.lastrun:
735
self.set_run_name(self.results.lastrun)
737
raise self.InvalidCmd('No run_name currently define. Unable to run refine')
741
raise self.InvalidCmd('Too many argument for refine command')
744
[float(arg) for arg in args]
747
raise self.InvalidCmd('refine arguments are suppose to be number')
751
def check_compute_widths(self, args):
752
"""check that the model is loadable and check that the format is of the
753
type: PART PATH --output=PATH -f
757
# Check that MG5 directory is present .
758
if MADEVENT and not self.options['mg5_path']:
759
raise self.InvalidCmd, '''The automatic computations of widths requires that MG5 is installed on the system.
760
You can install it and set his path in ./Cards/me5_configuration.txt'''
762
sys.path.append(self.options['mg5_path'])
764
import models.model_reader as model_reader
765
import models.import_ufo as import_ufo
767
raise self.ConfigurationError, '''Can\'t load MG5.
768
The variable mg5_path should not be correctly configure.'''
770
ufo_path = pjoin(self.me_dir,'bin','internal', 'ufomodel')
773
modelname = self.find_model_name()
775
if os.path.exists(pjoin(ufo_path, 'restrict_default.dat')):
776
restrict_file = pjoin(ufo_path, 'restrict_default.dat')
777
model = import_ufo.import_model(modelname, decay=True,
778
restrict_file=restrict_file)
779
if self.mother.options['complex_mass_scheme']:
780
model.change_mass_to_complex_scheme()
784
model = import_ufo.import_model(pjoin(self.me_dir,'bin','internal', 'ufomodel'),
786
#pattern for checking complex mass scheme.
787
has_cms = re.compile(r'''set\s+complex_mass_scheme\s*(True|T|1|true|$|;)''')
788
if has_cms.search(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')\
790
model.change_mass_to_complex_scheme()
794
if not hasattr(model.get('particles')[0], 'partial_widths'):
795
raise self.InvalidCmd, 'The UFO model does not include partial widths information. Impossible to compute widths automatically'
797
# check if the name are passed to default MG5
798
if '-modelname' in open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')).read():
799
model.pass_particles_name_in_mg_default()
800
model = model_reader.ModelReader(model)
801
particles_name = dict([(p.get('name'), p.get('pdg_code'))
802
for p in model.get('particles')])
804
output = {'model': model, 'model':model, 'force': False, 'output': None,
805
'input':None, 'particles': set()}
807
if arg.startswith('--output='):
808
output_path = arg.split('=',1)[1]
809
if not os.path.exists(output_path):
810
raise self.InvalidCmd, 'Invalid Path for the output. Please retry.'
811
if not os.path.isfile(output_path):
812
output_path = pjoin(output_path, 'param_card.dat')
813
output['output'] = output_path
815
output['force'] = True
816
elif os.path.isfile(arg):
817
type = self.detect_card_type(arg)
818
if type != 'param_card.dat':
819
raise self.InvalidCmd , '%s is not a valid param_card.' % arg
820
output['input'] = arg
821
elif arg in particles_name:
822
# should be a particles
823
output['particles'].add(particles_name[arg])
824
elif arg.isdigit() and int(arg) in particles_name.values():
825
output['particles'].add(eval(arg))
827
self.help_compute_widths()
828
raise self.InvalidCmd, '%s is not a valid argument for compute_widths' % arg
830
if not output['particles']:
831
raise self.InvalidCmd, '''This routines requires at least one particle in order to compute
834
if output['output'] is None:
835
output['output'] = output['input']
839
def check_combine_events(self, arg):
840
""" Check the argument for the combine events command """
842
tag = [a for a in arg if a.startswith('--tag=')]
846
elif not self.run_tag:
853
self.help_combine_events()
854
raise self.InvalidCmd('Too many argument for combine_events command')
857
self.set_run_name(arg[0], self.run_tag, 'parton', True)
859
if not self.run_name:
860
if not self.results.lastrun:
861
raise self.InvalidCmd('No run_name currently define. Unable to run combine')
863
self.set_run_name(self.results.lastrun)
867
def check_pythia(self, args):
868
"""Check the argument for pythia command
869
syntax: pythia [NAME]
870
Note that other option are already remove at this point
874
laststep = [arg for arg in args if arg.startswith('--laststep=')]
875
if laststep and len(laststep)==1:
876
mode = laststep[0].split('=')[-1]
877
if mode not in ['auto', 'pythia', 'pgs', 'delphes']:
879
raise self.InvalidCmd('invalid %s argument'% args[-1])
881
raise self.InvalidCmd('only one laststep argument is allowed')
883
# If not pythia-pgs path
884
if not self.options['pythia-pgs_path']:
885
logger.info('Retry to read configuration file to find pythia-pgs path')
886
self.set_configuration()
888
if not self.options['pythia-pgs_path'] or not \
889
os.path.exists(pjoin(self.options['pythia-pgs_path'],'src')):
890
error_msg = 'No pythia-pgs path correctly set.'
891
error_msg += 'Please use the set command to define the path and retry.'
892
error_msg += 'You can also define it in the configuration file.'
893
raise self.InvalidCmd(error_msg)
897
tag = [a for a in args if a.startswith('--tag=')]
902
if len(args) == 0 and not self.run_name:
903
if self.results.lastrun:
904
args.insert(0, self.results.lastrun)
906
raise self.InvalidCmd('No run name currently define. Please add this information.')
909
if args[0] != self.run_name and\
910
not os.path.exists(pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe.gz')):
911
raise self.InvalidCmd('No events file corresponding to %s run. '% args[0])
912
self.set_run_name(args[0], tag, 'pythia')
915
self.run_card['run_tag'] = tag
916
self.set_run_name(self.run_name, tag, 'pythia')
918
if not os.path.exists(pjoin(self.me_dir,'Events',self.run_name,'unweighted_events.lhe.gz')):
919
raise self.InvalidCmd('No events file corresponding to %s run. '% self.run_name)
921
input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe')
922
output_file = pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')
923
os.system('gunzip -c %s > %s' % (input_file, output_file))
927
def check_remove(self, args):
928
"""Check that the remove command is valid"""
932
tag = [a[6:] for a in tmp_args if a.startswith('--tag=')]
935
tmp_args.remove('--tag=%s' % tag)
938
if len(tmp_args) == 0:
940
raise self.InvalidCmd('clean command require the name of the run to clean')
941
elif len(tmp_args) == 1:
942
return tmp_args[0], tag, ['all']
944
for arg in tmp_args[1:]:
945
if arg not in self._clean_mode:
947
raise self.InvalidCmd('%s is not a valid options for clean command'\
949
return tmp_args[0], tag, tmp_args[1:]
951
def check_plot(self, args):
952
"""Check the argument for the plot command
953
plot run_name modes"""
955
madir = self.options['madanalysis_path']
956
td = self.options['td_path']
958
if not madir or not td:
959
logger.info('Retry to read configuration file to find madanalysis/td')
960
self.set_configuration()
962
madir = self.options['madanalysis_path']
963
td = self.options['td_path']
966
error_msg = 'No Madanalysis path correctly set.'
967
error_msg += 'Please use the set command to define the path and retry.'
968
error_msg += 'You can also define it in the configuration file.'
969
raise self.InvalidCmd(error_msg)
971
error_msg = 'No path to td directory correctly set.'
972
error_msg += 'Please use the set command to define the path and retry.'
973
error_msg += 'You can also define it in the configuration file.'
974
raise self.InvalidCmd(error_msg)
977
if not hasattr(self, 'run_name') or not self.run_name:
979
raise self.InvalidCmd('No run name currently define. Please add this information.')
984
if args[0] not in self._plot_mode:
985
self.set_run_name(args[0], level='plot')
989
elif not self.run_name:
991
raise self.InvalidCmd('No run name currently define. Please add this information.')
994
if arg not in self._plot_mode and arg != self.run_name:
996
raise self.InvalidCmd('unknown options %s' % arg)
999
def check_pgs(self, arg):
1000
"""Check the argument for pythia command
1002
Note that other option are already remove at this point
1005
# If not pythia-pgs path
1006
if not self.options['pythia-pgs_path']:
1007
logger.info('Retry to read configuration file to find pythia-pgs path')
1008
self.set_configuration()
1010
if not self.options['pythia-pgs_path'] or not \
1011
os.path.exists(pjoin(self.options['pythia-pgs_path'],'src')):
1012
error_msg = 'No pythia-pgs path correctly set.'
1013
error_msg += 'Please use the set command to define the path and retry.'
1014
error_msg += 'You can also define it in the configuration file.'
1015
raise self.InvalidCmd(error_msg)
1017
tag = [a for a in arg if a.startswith('--tag=')]
1023
if len(arg) == 0 and not self.run_name:
1024
if self.results.lastrun:
1025
arg.insert(0, self.results.lastrun)
1027
raise self.InvalidCmd('No run name currently define. Please add this information.')
1029
if len(arg) == 1 and self.run_name == arg[0]:
1032
if not len(arg) and \
1033
not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')):
1035
raise self.InvalidCmd('''No file file pythia_events.hep currently available
1036
Please specify a valid run_name''')
1040
prev_tag = self.set_run_name(arg[0], tag, 'pgs')
1041
if not os.path.exists(pjoin(self.me_dir,'Events',self.run_name,'%s_pythia_events.hep.gz' % prev_tag)):
1042
raise self.InvalidCmd('No events file corresponding to %s run with tag %s. '% (self.run_name, prev_tag))
1044
input_file = pjoin(self.me_dir,'Events', self.run_name, '%s_pythia_events.hep.gz' % prev_tag)
1045
output_file = pjoin(self.me_dir, 'Events', 'pythia_events.hep')
1046
lock = cluster.asyncrone_launch('gunzip',stdout=open(output_file,'w'),
1047
argument=['-c', input_file])
1051
self.run_card['run_tag'] = tag
1052
self.set_run_name(self.run_name, tag, 'pgs')
1056
def check_delphes(self, arg):
1057
"""Check the argument for pythia command
1058
syntax: delphes [NAME]
1059
Note that other option are already remove at this point
1062
# If not pythia-pgs path
1063
if not self.options['delphes_path']:
1064
logger.info('Retry to read configuration file to find delphes path')
1065
self.set_configuration()
1067
if not self.options['delphes_path']:
1068
error_msg = 'No delphes path correctly set.'
1069
error_msg += 'Please use the set command to define the path and retry.'
1070
error_msg += 'You can also define it in the configuration file.'
1071
raise self.InvalidCmd(error_msg)
1073
tag = [a for a in arg if a.startswith('--tag=')]
1079
if len(arg) == 0 and not self.run_name:
1080
if self.results.lastrun:
1081
arg.insert(0, self.results.lastrun)
1083
raise self.InvalidCmd('No run name currently define. Please add this information.')
1085
if len(arg) == 1 and self.run_name == arg[0]:
1088
if not len(arg) and \
1089
not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')):
1091
raise self.InvalidCmd('''No file file pythia_events.hep currently available
1092
Please specify a valid run_name''')
1096
prev_tag = self.set_run_name(arg[0], tag, 'delphes')
1097
if not os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)):
1098
raise self.InvalidCmd('No events file corresponding to %s run with tag %s.:%s '\
1099
% (self.run_name, prev_tag,
1100
pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)))
1102
input_file = pjoin(self.me_dir,'Events', self.run_name, '%s_pythia_events.hep.gz' % prev_tag)
1103
output_file = pjoin(self.me_dir, 'Events', 'pythia_events.hep')
1104
lock = cluster.asyncrone_launch('gunzip',stdout=open(output_file,'w'),
1105
argument=['-c', input_file])
1108
self.run_card['run_tag'] = tag
1109
self.set_run_name(self.run_name, tag, 'delphes')
1113
def check_display(self, args):
1114
"""check the validity of line
1115
syntax: display XXXXX
1118
if len(args) < 1 or args[0] not in self._display_opts:
1120
raise self.InvalidCmd
1122
if args[0] == 'variable' and len(args) !=2:
1123
raise self.InvalidCmd('variable need a variable name')
1129
def check_import(self, args):
1130
"""check the validity of line"""
1134
raise self.InvalidCmd('wrong \"import\" format')
1136
if args[0] != 'command':
1137
args.insert(0,'command')
1140
if not len(args) == 2 or not os.path.exists(args[1]):
1141
raise self.InvalidCmd('PATH is mandatory for import command\n')
1144
#===============================================================================
1146
#===============================================================================
1147
class CompleteForCmd(CheckValidForCmd):
1148
""" The Series of help routine for the MadGraphCmd"""
1151
def complete_add_time_of_flight(self, text, line, begidx, endidx):
1154
args = self.split_arg(line[0:begidx], error=False)
1157
#return valid run_name
1158
data = glob.glob(pjoin(self.me_dir, 'Events', '*','unweighted_events.lhe.gz'))
1159
data = [n.rsplit('/',2)[1] for n in data]
1160
return self.list_completion(text, data + ['--threshold='], line)
1161
elif args[-1].endswith(os.path.sep):
1162
return self.path_completion(text,
1163
os.path.join('.',*[a for a in args \
1164
if a.endswith(os.path.sep)]))
1166
return self.list_completion(text, ['--threshold='], line)
1168
def complete_banner_run(self, text, line, begidx, endidx):
1169
"Complete the banner run command"
1173
args = self.split_arg(line[0:begidx], error=False)
1175
if args[-1].endswith(os.path.sep):
1176
return self.path_completion(text,
1177
os.path.join('.',*[a for a in args \
1178
if a.endswith(os.path.sep)]))
1182
# only options are possible
1183
tags = glob.glob(pjoin(self.me_dir, 'Events' , args[1],'%s_*_banner.txt' % args[1]))
1184
tags = ['%s' % os.path.basename(t)[len(args[1])+1:-11] for t in tags]
1186
if args[-1] != '--tag=':
1187
tags = ['--tag=%s' % t for t in tags]
1189
return self.list_completion(text, tags)
1190
return self.list_completion(text, tags +['--name=','-f'], line)
1195
comp = self.path_completion(text, os.path.join('.',*[a for a in args \
1196
if a.endswith(os.path.sep)]))
1197
if os.path.sep in line:
1200
possibilites['Path from ./'] = comp
1202
run_list = glob.glob(pjoin(self.me_dir, 'Events', '*','*_banner.txt'))
1203
run_list = [n.rsplit('/',2)[1] for n in run_list]
1204
possibilites['RUN Name'] = self.list_completion(text, run_list)
1206
return self.deal_multiple_categories(possibilites)
1209
except Exception, error:
1211
def complete_history(self, text, line, begidx, endidx):
1212
"Complete the history command"
1214
args = self.split_arg(line[0:begidx], error=False)
1216
# Directory continuation
1217
if args[-1].endswith(os.path.sep):
1218
return self.path_completion(text,
1219
os.path.join('.',*[a for a in args \
1220
if a.endswith(os.path.sep)]))
1223
return self.path_completion(text)
1225
def complete_open(self, text, line, begidx, endidx):
1226
""" complete the open command """
1228
args = self.split_arg(line[0:begidx])
1230
# Directory continuation
1231
if os.path.sep in args[-1] + text:
1232
return self.path_completion(text,
1233
os.path.join('.',*[a for a in args if \
1234
a.endswith(os.path.sep)]))
1239
possibility = ['index.html']
1240
if os.path.isfile(os.path.join(path,'README')):
1241
possibility.append('README')
1242
if os.path.isdir(os.path.join(path,'Cards')):
1243
possibility += [f for f in os.listdir(os.path.join(path,'Cards'))
1244
if f.endswith('.dat')]
1245
if os.path.isdir(os.path.join(path,'HTML')):
1246
possibility += [f for f in os.listdir(os.path.join(path,'HTML'))
1247
if f.endswith('.html') and 'default' not in f]
1249
possibility.extend(['./','../'])
1250
if os.path.exists('ME5_debug'):
1251
possibility.append('ME5_debug')
1252
if os.path.exists('MG5_debug'):
1253
possibility.append('MG5_debug')
1254
return self.list_completion(text, possibility)
1256
def complete_set(self, text, line, begidx, endidx):
1257
"Complete the set command"
1259
args = self.split_arg(line[0:begidx])
1263
return self.list_completion(text, self._set_options + self.options.keys() )
1266
if args[1] == 'stdout_level':
1267
return self.list_completion(text, ['DEBUG','INFO','WARNING','ERROR','CRITICAL'])
1269
first_set = ['None','True','False']
1271
second_set = [name for name in self.path_completion(text, '.', only_dirs = True)]
1272
return self.list_completion(text, first_set + second_set)
1273
elif len(args) >2 and args[-1].endswith(os.path.sep):
1274
return self.path_completion(text,
1275
os.path.join('.',*[a for a in args if a.endswith(os.path.sep)]),
1278
def complete_survey(self, text, line, begidx, endidx):
1279
""" Complete the survey command """
1281
if line.endswith('nb_core=') and not text:
1282
import multiprocessing
1283
max = multiprocessing.cpu_count()
1284
return [str(i) for i in range(2,max+1)]
1286
return self.list_completion(text, self._run_options, line)
1288
complete_refine = complete_survey
1289
complete_combine_events = complete_survey
1290
complite_store = complete_survey
1291
complete_generate_events = complete_survey
1292
complete_create_gridpack = complete_survey
1294
def complete_generate_events(self, text, line, begidx, endidx):
1295
""" Complete the generate events"""
1297
if line.endswith('nb_core=') and not text:
1298
import multiprocessing
1299
max = multiprocessing.cpu_count()
1300
return [str(i) for i in range(2,max+1)]
1301
if line.endswith('laststep=') and not text:
1302
return ['parton','pythia','pgs','delphes']
1303
elif '--laststep=' in line.split()[-1] and line and line[-1] != ' ':
1304
return self.list_completion(text,['parton','pythia','pgs','delphes'],line)
1306
opts = self._run_options + self._generate_options
1307
return self.list_completion(text, opts, line)
1309
def complete_launch(self, *args, **opts):
1311
if self.ninitial == 1:
1312
return self.complete_calculate_decay_widths(*args, **opts)
1314
return self.complete_generate_events(*args, **opts)
1317
def complete_calculate_decay_widths(self, text, line, begidx, endidx):
1318
""" Complete the calculate_decay_widths command"""
1320
if line.endswith('nb_core=') and not text:
1321
import multiprocessing
1322
max = multiprocessing.cpu_count()
1323
return [str(i) for i in range(2,max+1)]
1325
opts = self._run_options + self._calculate_decay_options
1326
return self.list_completion(text, opts, line)
1328
def complete_multi_run(self, text, line, begidx, endidx):
1329
"""complete multi run command"""
1331
args = self.split_arg(line[0:begidx], error=False)
1333
data = [str(i) for i in range(0,20)]
1334
return self.list_completion(text, data, line)
1336
if line.endswith('run=') and not text:
1337
return ['parton','pythia','pgs','delphes']
1338
elif '--laststep=' in line.split()[-1] and line and line[-1] != ' ':
1339
return self.list_completion(text,['parton','pythia','pgs','delphes'],line)
1341
opts = self._run_options + self._generate_options
1342
return self.list_completion(text, opts, line)
1346
if line.endswith('nb_core=') and not text:
1347
import multiprocessing
1348
max = multiprocessing.cpu_count()
1349
return [str(i) for i in range(2,max+1)]
1350
opts = self._run_options + self._generate_options
1351
return self.list_completion(text, opts, line)
1353
def complete_plot(self, text, line, begidx, endidx):
1354
""" Complete the plot command """
1356
args = self.split_arg(line[0:begidx], error=False)
1358
return self.list_completion(text, self._plot_mode)
1360
return self.list_completion(text, self._plot_mode + self.results.keys())
1362
def complete_remove(self, text, line, begidx, endidx):
1363
"""Complete the remove command """
1365
args = self.split_arg(line[0:begidx], error=False)
1366
if len(args) > 1 and (text.startswith('--t')):
1368
tags = ['--tag=%s' % tag['tag'] for tag in self.results[run]]
1369
return self.list_completion(text, tags)
1370
elif len(args) > 1 and '--' == args[-1]:
1372
tags = ['tag=%s' % tag['tag'] for tag in self.results[run]]
1373
return self.list_completion(text, tags)
1374
elif len(args) > 1 and '--tag=' == args[-1]:
1376
tags = [tag['tag'] for tag in self.results[run]]
1377
return self.list_completion(text, tags)
1379
return self.list_completion(text, self._clean_mode + ['-f','--tag='])
1381
data = glob.glob(pjoin(self.me_dir, 'Events','*','*_banner.txt'))
1382
data = [n.rsplit('/',2)[1] for n in data]
1383
return self.list_completion(text, ['all'] + data)
1386
def complete_pythia(self,text, line, begidx, endidx):
1387
"Complete the pythia command"
1388
args = self.split_arg(line[0:begidx], error=False)
1391
#return valid run_name
1392
data = glob.glob(pjoin(self.me_dir, 'Events', '*','unweighted_events.lhe.gz'))
1393
data = [n.rsplit('/',2)[1] for n in data]
1394
tmp1 = self.list_completion(text, data)
1395
if not self.run_name:
1398
tmp2 = self.list_completion(text, self._run_options + ['-f',
1399
'--no_default', '--tag='], line)
1401
elif line[-1] != '=':
1402
return self.list_completion(text, self._run_options + ['-f',
1403
'--no_default','--tag='], line)
1405
def complete_pgs(self,text, line, begidx, endidx):
1406
"Complete the pythia command"
1407
args = self.split_arg(line[0:begidx], error=False)
1409
#return valid run_name
1410
data = glob.glob(pjoin(self.me_dir, 'Events', '*', '*_pythia_events.hep.gz'))
1411
data = [n.rsplit('/',2)[1] for n in data]
1412
tmp1 = self.list_completion(text, data)
1413
if not self.run_name:
1416
tmp2 = self.list_completion(text, self._run_options + ['-f',
1417
'--tag=' ,'--no_default'], line)
1420
return self.list_completion(text, self._run_options + ['-f',
1421
'--tag=','--no_default'], line)
1423
complete_delphes = complete_pgs
1428
#===============================================================================
1430
#===============================================================================
1431
class MadEventCmd(CmdExtended, HelpToCmd, CompleteForCmd, common_run.CommonRunCmd):
1432
"""The command line processor of MadGraph"""
1435
true = ['T','.true.',True,'true']
1436
# Options and formats available
1437
_run_options = ['--cluster','--multicore','--nb_core=','--nb_core=2', '-c', '-m']
1438
_generate_options = ['-f', '--laststep=parton', '--laststep=pythia', '--laststep=pgs', '--laststep=delphes']
1439
_calculate_decay_options = ['-f', '--accuracy=0.']
1440
_set_options = ['stdout_level','fortran_compiler','timeout']
1441
_plot_mode = ['all', 'parton','pythia','pgs','delphes','channel', 'banner']
1442
_clean_mode = _plot_mode
1443
_display_opts = ['run_name', 'options', 'variable']
1444
# survey options, dict from name to type, default value, and help text
1445
_survey_options = {'points':('int', 1000,'Number of points for first iteration'),
1446
'iterations':('int', 5, 'Number of iterations'),
1447
'accuracy':('float', 0.1, 'Required accuracy'),
1448
'gridpack':('str', '.false.', 'Gridpack generation')}
1449
# Variables to store object information
1450
true = ['T','.true.',True,'true', 1, '1']
1457
next_possibility = {
1458
'start': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]',
1459
'calculate_decay_widths [OPTIONS]',
1460
'help generate_events'],
1461
'generate_events': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]', 'pythia', 'pgs','delphes'],
1462
'calculate_decay_widths': ['calculate_decay_widths [OPTIONS]',
1463
'generate_events [OPTIONS]'],
1464
'multi_run': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'],
1465
'survey': ['refine'],
1466
'refine': ['combine_events'],
1467
'combine_events': ['store'],
1468
'store': ['pythia'],
1469
'pythia': ['pgs', 'delphes'],
1470
'pgs': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'],
1471
'delphes' : ['generate_events [OPTIONS]', 'multi_run [OPTIONS]']
1474
############################################################################
1475
def __init__(self, me_dir = None, options={}, *completekey, **stdin):
1476
""" add information to the cmd """
1478
CmdExtended.__init__(self, me_dir, options, *completekey, **stdin)
1479
#common_run.CommonRunCmd.__init__(self, me_dir, options)
1482
self.mode = 'madevent'
1485
os.system('touch %s' % pjoin(self.me_dir,'Online'))
1488
# load the current status of the directory
1489
if os.path.exists(pjoin(self.me_dir,'HTML','results.pkl')):
1490
self.results = save_load_object.load_from_file(pjoin(self.me_dir,'HTML','results.pkl'))
1491
self.results.resetall(self.me_dir)
1493
model = self.find_model_name()
1494
process = self.process # define in find_model_name
1495
self.results = gen_crossxhtml.AllResults(model, process, self.me_dir)
1496
self.results.def_web_mode(self.web)
1497
gen_crossxhtml.GenCardHTML(self.results)
1499
self.configured = 0 # time for reading the card
1500
self._options = {} # for compatibility with extended_cmd
1502
def pass_in_web_mode(self):
1503
"""configure web data"""
1505
self.results.def_web_mode(True)
1508
############################################################################
1509
def check_output_type(self, path):
1510
""" Check that the output path is a valid madevent directory """
1512
bin_path = os.path.join(path,'bin')
1513
if os.path.isfile(os.path.join(bin_path,'generate_events')):
1518
############################################################################
1519
def do_add_time_of_flight(self, line):
1521
args = self.split_arg(line)
1522
#check the validity of the arguments and reformat args
1523
self.check_add_time_of_flight(args)
1525
event_path, threshold = args
1527
if event_path.endswith('.gz'):
1529
subprocess.call(['gunzip', event_path])
1530
event_path = event_path[:-3]
1536
import madgraph.various.lhe_parser as lhe_parser
1538
import internal.lhe_parser as lhe_parser
1540
logger.info('Add time of flight information on file %s' % event_path)
1541
lhe = lhe_parser.EventFile(event_path)
1542
output = open('%s_2vertex.lhe' % event_path, 'w')
1543
#write the banner to the output file
1544
output.write(lhe.banner)
1546
# get the associate param_card
1547
begin_param = lhe.banner.find('<slha>')
1548
end_param = lhe.banner.find('</slha>')
1549
param_card = lhe.banner[begin_param+6:end_param].split('\n')
1550
param_card = check_param_card.ParamCard(param_card)
1552
cst = 6.58211915e-25
1553
# Loop over all events
1555
for particle in event:
1557
width = param_card['decay'].get((abs(id),)).value
1559
vtim = random.expovariate(width/cst)
1560
if vtim > threshold:
1561
particle.vtim = vtim
1562
#write this modify event
1563
output.write(str(event))
1564
output.write('</LesHouchesEvents>\n')
1567
files.mv('%s_2vertex.lhe' % event_path, event_path)
1570
subprocess.call(['gzip', event_path])
1572
############################################################################
1573
def do_banner_run(self, line):
1574
"""Make a run from the banner file"""
1576
args = self.split_arg(line)
1577
#check the validity of the arguments
1578
self.check_banner_run(args)
1580
# Remove previous cards
1581
for name in ['delphes_trigger.dat', 'delphes_card.dat',
1582
'pgs_card.dat', 'pythia_card.dat']:
1584
os.remove(pjoin(self.me_dir, 'Cards', name))
1588
banner_mod.split_banner(args[0], self.me_dir, proc_card=False)
1590
# Check if we want to modify the run
1592
ans = self.ask('Do you want to modify the Cards?', 'n', ['y','n'])
1596
# Call Generate events
1597
self.exec_cmd('generate_events %s %s' % (self.run_name, self.force and '-f' or ''))
1601
############################################################################
1602
def do_display(self, line, output=sys.stdout):
1603
"""Display current internal status"""
1605
args = self.split_arg(line)
1606
#check the validity of the arguments
1607
self.check_display(args)
1609
if args[0] == 'run_name':
1610
#return valid run_name
1611
data = glob.glob(pjoin(self.me_dir, 'Events', '*','*_banner.txt'))
1612
data = [n.rsplit('/',2)[1:] for n in data]
1616
for name, tag in data:
1617
tag = tag[len(name)+1:-11]
1619
out[name].append(tag)
1622
print 'the runs available are:'
1623
for run_name, tags in out.items():
1624
print ' run: %s' % run_name
1626
print ', '.join(tags)
1628
print 'No run detected.'
1630
elif args[0] == 'options':
1631
outstr = " Run Options \n"
1632
outstr += " ----------- \n"
1633
for key, default in self.options_madgraph.items():
1634
value = self.options[key]
1635
if value == default:
1636
outstr += " %25s \t:\t%s\n" % (key,value)
1638
outstr += " %25s \t:\t%s (user set)\n" % (key,value)
1640
outstr += " MadEvent Options \n"
1641
outstr += " ---------------- \n"
1642
for key, default in self.options_madevent.items():
1643
value = self.options[key]
1644
if value == default:
1645
outstr += " %25s \t:\t%s\n" % (key,value)
1647
outstr += " %25s \t:\t%s (user set)\n" % (key,value)
1649
outstr += " Configuration Options \n"
1650
outstr += " --------------------- \n"
1651
for key, default in self.options_configuration.items():
1652
value = self.options[key]
1653
if value == default:
1654
outstr += " %25s \t:\t%s\n" % (key,value)
1656
outstr += " %25s \t:\t%s (user set)\n" % (key,value)
1657
output.write(outstr)
1659
super(MadEventCmd, self).do_display(line, output)
1661
def do_save(self, line, check=True, to_keep={}):
1662
"""Not in help: Save information to file"""
1664
args = self.split_arg(line)
1665
# Check argument validity
1667
self.check_save(args)
1669
if args[0] == 'options':
1670
# First look at options which should be put in MG5DIR/input
1672
for key, default in self.options_configuration.items():
1673
if self.options[key] != self.options_configuration[key]:
1674
to_define[key] = self.options[key]
1676
if not '--auto' in args:
1677
for key, default in self.options_madevent.items():
1678
if self.options[key] != self.options_madevent[key]:
1679
to_define[key] = self.options[key]
1682
for key, default in self.options_madgraph.items():
1683
if self.options[key] != self.options_madgraph[key]:
1684
to_define[key] = self.options[key]
1685
elif not '--auto' in args:
1686
for key, default in self.options_madgraph.items():
1687
if self.options[key] != self.options_madgraph[key]:
1688
logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \
1689
% (key,self.options_madgraph[key]) )
1690
logger.info('If you want to make this value the default for future session, you can run \'save options --all\'')
1691
if len(args) >1 and not args[1].startswith('--'):
1694
filepath = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1695
basefile = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1696
basedir = self.me_dir
1700
self.write_configuration(filepath, basefile, basedir, to_define)
1702
############################################################################
1703
def do_import(self, line):
1704
"""Advanced commands: Import command files"""
1706
args = self.split_arg(line)
1707
# Check argument's validity
1708
self.check_import(args)
1711
self.import_command_file(args[1])
1714
def post_set(self, stop, line):
1715
"""Check if we need to save this in the option file"""
1717
args = self.split_arg(line)
1718
# Check the validity of the arguments
1719
self.check_set(args)
1721
if args[0] in self.options_configuration and '--no_save' not in args:
1722
self.exec_cmd('save options --auto')
1723
elif args[0] in self.options_madevent:
1724
logger.info('This option will be the default in any output that you are going to create in this session.')
1725
logger.info('In order to keep this changes permanent please run \'save options\'')
1727
except self.InvalidCmd:
1730
############################################################################
1731
def do_generate_events(self, line):
1732
"""Main commands: launch the full chain """
1737
args = self.split_arg(line)
1738
# Check argument's validity
1739
mode = self.check_generate_events(args)
1740
self.ask_run_configuration(mode)
1742
# No run name assigned -> assigned one automaticaly
1743
self.set_run_name(self.find_available_run_name(self.me_dir), None, 'parton')
1745
self.set_run_name(args[0], None, 'parton', True)
1748
if self.run_card['gridpack'] in self.true:
1749
# Running gridpack warmup
1750
gridpack_opts=[('accuracy', 0.01),
1753
('gridpack','.true.')]
1754
logger.info('Generating gridpack with run name %s' % self.run_name)
1755
self.exec_cmd('survey %s %s' % \
1757
" ".join(['--' + opt + '=' + str(val) for (opt,val) \
1758
in gridpack_opts])),
1760
self.exec_cmd('combine_events', postcmd=False)
1761
self.exec_cmd('store_events', postcmd=False)
1762
self.exec_cmd('create_gridpack', postcmd=False)
1765
logger.info('Generating %s events with run name %s' %
1766
(self.run_card['nevents'], self.run_name))
1768
self.exec_cmd('survey %s %s' % (self.run_name,' '.join(args)),
1770
if not float(self.results.current['cross']):
1771
# Zero cross-section. Try to guess why
1772
text = '''Survey return zero cross section.
1773
Typical reasons are the following:
1774
1) A massive s-channel particle has a width set to zero.
1775
2) The pdf are zero for at least one of the initial state particles
1776
or you are using maxjetflavor=4 for initial state b:s.
1777
3) The cuts are too strong.
1778
Please check/correct your param_card and/or your run_card.'''
1779
logger_stderr.critical(text)
1780
raise ZeroResult('See https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/FAQ-General-14')
1781
nb_event = self.run_card['nevents']
1782
self.exec_cmd('refine %s' % nb_event, postcmd=False)
1783
self.exec_cmd('refine %s' % nb_event, postcmd=False)
1784
self.exec_cmd('combine_events', postcmd=False)
1785
self.print_results_in_shell(self.results.current)
1786
self.create_plot('parton')
1787
self.exec_cmd('store_events', postcmd=False)
1788
self.exec_cmd('decay_events -from_cards', postcmd=False)
1789
self.exec_cmd('pythia --no_default', postcmd=False, printcmd=False)
1790
# pythia launches pgs/delphes if needed
1794
def do_launch(self, line, *args, **opt):
1795
"""Main commands:exec generate_events for 2>N and calculate_width for 1>N"""
1796
if self.ninitial == 1:
1797
self.do_calculate_decay_widths(line, *args, **opt)
1799
self.do_generate_events(line, *args, **opt)
1801
def print_results_in_shell(self, data):
1802
"""Have a nice results prints in the shell,
1803
data should be of type: gen_crossxhtml.OneTagResults"""
1806
logger.info(" === Results Summary for run: %s tag: %s ===\n" % (data['run_name'],data['tag']))
1807
if self.ninitial == 1:
1808
logger.info(" Width : %.4g +- %.4g GeV" % (data['cross'], data['error']))
1810
logger.info(" Cross-section : %.4g +- %.4g pb" % (data['cross'], data['error']))
1811
logger.info(" Nb of events : %s" % data['nb_event'] )
1812
if data['cross_pythia'] and data['nb_event_pythia']:
1813
if self.ninitial == 1:
1814
logger.info(" Matched Width : %.4g +- %.4g GeV" % (data['cross_pythia'], data['error_pythia']))
1816
logger.info(" Matched Cross-section : %.4g +- %.4g pb" % (data['cross_pythia'], data['error_pythia']))
1817
logger.info(" Nb of events after Matching : %s" % data['nb_event_pythia'])
1820
############################################################################
1821
def do_calculate_decay_widths(self, line):
1822
"""Main commands:launch decay width calculation and automatic inclusion of
1823
calculated widths and BRs in the param_card."""
1826
args = self.split_arg(line)
1827
# Check argument's validity
1828
accuracy = self.check_calculate_decay_widths(args)
1829
self.ask_run_configuration('parton')
1831
# No run name assigned -> assigned one automaticaly
1832
self.set_run_name(self.find_available_run_name(self.me_dir))
1834
self.set_run_name(args[0], reload_card=True)
1837
# Running gridpack warmup
1838
opts=[('accuracy', accuracy), # default 0.01
1842
logger.info('Calculating decay widths with run name %s' % self.run_name)
1844
self.exec_cmd('survey %s %s' % \
1846
" ".join(['--' + opt + '=' + str(val) for (opt,val) \
1849
self.exec_cmd('combine_events', postcmd=False)
1850
self.exec_cmd('store_events', postcmd=False)
1852
self.collect_decay_widths()
1853
self.update_status('calculate_decay_widths done',
1854
level='parton', makehtml=False)
1857
############################################################################
1858
def collect_decay_widths(self):
1859
""" Collect the decay widths and calculate BRs for all particles, and put
1863
particle_dict = {} # store the results
1864
run_name = self.run_name
1866
# Looping over the Subprocesses
1867
for P_path in SubProcesses.get_subP(self.me_dir):
1868
ids = SubProcesses.get_subP_ids(P_path)
1869
# due to grouping we need to compute the ratio factor for the
1870
# ungroup resutls (that we need here). Note that initial particles
1871
# grouping are not at the same stage as final particle grouping
1872
nb_output = len(ids) / (len(set([p[0] for p in ids])))
1873
results = open(pjoin(P_path, run_name + '_results.dat')).read().split('\n')[0]
1874
result = float(results.strip().split(' ')[0])
1875
for particles in ids:
1877
particle_dict[particles[0]].append([particles[1:], result/nb_output])
1879
particle_dict[particles[0]] = [[particles[1:], result/nb_output]]
1881
self.update_width_in_param_card(particle_dict,
1882
initial = pjoin(self.me_dir, 'Cards', 'param_card.dat'),
1883
output=pjoin(self.me_dir, 'Events', run_name, "param_card.dat"))
1886
def update_width_in_param_card(decay_info, initial, output=None):
1887
# Open the param_card.dat and insert the calculated decays and BRs
1892
param_card_file = open(initial)
1893
param_card = param_card_file.read().split('\n')
1894
param_card_file.close()
1898
# Read and remove all decays from the param_card
1899
while line_number < len(param_card):
1900
line = param_card[line_number]
1901
if line.lower().startswith('decay'):
1902
# Read decay if particle in decay_info
1903
# DECAY 6 1.455100e+00
1904
line = param_card.pop(line_number)
1907
if int(line[1]) not in decay_info:
1908
try: # If formatting is wrong, don't want this particle
1909
particle = int(line[1])
1910
width = float(line[2])
1913
# Read BRs for this decay
1914
line = param_card[line_number]
1915
while line.startswith('#') or line.startswith(' '):
1916
line = param_card.pop(line_number)
1917
if not particle or line.startswith('#'):
1918
line=param_card[line_number]
1920
# 6.668201e-01 3 5 2 -1
1922
try: # Remove BR if formatting is wrong
1923
partial_width = float(line[0])*width
1924
decay_products = [int(p) for p in line[2:2+int(line[1])]]
1926
line=param_card[line_number]
1929
decay_info[particle].append([decay_products, partial_width])
1931
decay_info[particle] = [[decay_products, partial_width]]
1932
line=param_card[line_number]
1933
if particle and particle not in decay_info:
1934
# No decays given, only total width
1935
decay_info[particle] = [[[], width]]
1938
# Clean out possible remaining comments at the end of the card
1939
while not param_card[-1] or param_card[-1].startswith('#'):
1942
# Append calculated and read decays to the param_card
1943
param_card.append("#\n#*************************")
1944
param_card.append("# Decay widths *")
1945
param_card.append("#*************************")
1946
for key in sorted(decay_info.keys()):
1947
width = sum([r for p,r in decay_info[key]])
1948
param_card.append("#\n# PDG Width")
1949
param_card.append("DECAY %i %e" % (key, width.real))
1952
if decay_info[key][0][0]:
1953
param_card.append("# BR NDA ID1 ID2 ...")
1954
brs = [[(val[1]/width).real, val[0]] for val in decay_info[key] if val[1]]
1955
for val in sorted(brs, reverse=True):
1956
param_card.append(" %e %i %s # %s" %
1957
(val[0].real, len(val[1]),
1958
" ".join([str(v) for v in val[1]]),
1961
decay_table = open(output, 'w')
1962
decay_table.write("\n".join(param_card) + "\n")
1963
logger.info("Results written to %s" % output)
1965
############################################################################
1966
def do_multi_run(self, line):
1968
args = self.split_arg(line)
1969
# Check argument's validity
1970
mode = self.check_multi_run(args)
1971
nb_run = args.pop(0)
1973
logger.warn("'multi_run 1' command is not optimal. Think of using generate_events instead")
1974
self.ask_run_configuration(mode)
1975
main_name = self.run_name
1984
for i in range(nb_run):
1986
self.exec_cmd('generate_events %s_%s -f' % (main_name, i), postcmd=False)
1987
# Update collected value
1988
nb_event += int(self.results[self.run_name][-1]['nb_event'])
1989
self.results.add_detail('nb_event', nb_event , run=main_name)
1990
cross = self.results[self.run_name][-1]['cross']
1991
error = self.results[self.run_name][-1]['error'] + 1e-99
1992
crossoversig+=cross/error**2
1993
inv_sq_err+=1.0/error**2
1994
self.results[main_name][-1]['cross'] = crossoversig/inv_sq_err
1995
self.results[main_name][-1]['error'] = math.sqrt(1.0/inv_sq_err)
1996
self.results.def_current(main_name)
1997
self.run_name = main_name
1998
self.update_status("Merging LHE files", level='parton')
2000
os.mkdir(pjoin(self.me_dir,'Events', self.run_name))
2003
os.system('%(bin)s/merge.pl %(event)s/%(name)s_*/unweighted_events.lhe.gz %(event)s/%(name)s/unweighted_events.lhe.gz %(event)s/%(name)s_banner.txt'
2004
% {'bin': self.dirbin, 'event': pjoin(self.me_dir,'Events'),
2005
'name': self.run_name})
2007
eradir = self.options['exrootanalysis_path']
2008
if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter')):
2009
self.update_status("Create Root file", level='parton')
2010
os.system('gunzip %s/%s/unweighted_events.lhe.gz' %
2011
(pjoin(self.me_dir,'Events'), self.run_name))
2012
self.create_root_file('%s/unweighted_events.lhe' % self.run_name,
2013
'%s/unweighted_events.root' % self.run_name)
2016
self.create_plot('parton', '%s/%s/unweighted_events.lhe' %
2017
(pjoin(self.me_dir, 'Events'),self.run_name),
2018
pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html')
2021
os.system('gzip -f %s/%s/unweighted_events.lhe' %
2022
(pjoin(self.me_dir, 'Events'), self.run_name))
2024
self.update_status('', level='parton')
2025
self.print_results_in_shell(self.results.current)
2028
############################################################################
2029
def do_treatcards(self, line):
2030
"""Advanced commands: create .inc files from param_card.dat/run_card.dat"""
2032
args = self.split_arg(line)
2033
mode, opt = self.check_treatcards(args)
2035
#check if no 'Auto' are present in the file
2036
self.check_param_card(pjoin(self.me_dir, 'Cards','param_card.dat'))
2039
if mode in ['run', 'all']:
2040
if not hasattr(self, 'run_card'):
2041
run_card = banner_mod.RunCard(opt['run_card'])
2043
run_card = self.run_card
2044
run_card.write_include_file(pjoin(opt['output_dir'],'run_card.inc'))
2046
if mode in ['param', 'all']:
2047
model = self.find_model_name()
2048
if model == 'mssm' or model.startswith('mssm-'):
2049
if not '--param_card=' in line:
2050
param_card = pjoin(self.me_dir, 'Cards','param_card.dat')
2051
mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat')
2052
check_param_card.convert_to_mg5card(param_card, mg5_param)
2053
check_param_card.check_valid_param_card(mg5_param)
2054
opt['param_card'] = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat')
2056
logger.debug('write compile file for card: %s' % opt['param_card'])
2057
param_card = check_param_card.ParamCard(opt['param_card'])
2058
outfile = pjoin(opt['output_dir'], 'param_card.inc')
2059
ident_card = pjoin(self.me_dir,'Cards','ident_card.dat')
2060
if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')):
2061
default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')
2062
elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')):
2063
default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
2064
elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')):
2065
fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w')
2070
subprocess.call(['python', 'write_param_card.py'],
2071
cwd=pjoin(self.me_dir,'bin','internal','ufomodel'))
2072
default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
2073
param_card.write_inc_file(outfile, ident_card, default)
2075
############################################################################
2076
def do_survey(self, line):
2077
"""Advanced commands: launch survey for the current process """
2080
args = self.split_arg(line)
2081
# Check argument's validity
2082
self.check_survey(args)
2083
# initialize / remove lhapdf mode
2085
if os.path.exists(pjoin(self.me_dir,'error')):
2086
os.remove(pjoin(self.me_dir,'error'))
2088
self.configure_directory()
2089
# Save original random number
2090
self.random_orig = self.random
2091
logger.info("Using random number seed offset = %s" % self.random)
2092
# Update random number
2093
self.update_random()
2095
self.update_status('Running Survey', level=None)
2096
if self.cluster_mode:
2097
logger.info('Creating Jobs')
2099
logger.info('Working on SubProcesses')
2101
subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
2104
P_zero_result = [] # check the number of times where they are no phase-space
2105
for nb_proc,subdir in enumerate(subproc):
2106
subdir = subdir.strip()
2107
Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
2108
logger.info(' %s ' % subdir)
2109
# clean previous run
2110
for match in glob.glob(pjoin(Pdir, '*ajob*')):
2111
if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
2113
for match in glob.glob(pjoin(Pdir, 'G*')):
2114
if os.path.exists(pjoin(match,'results.dat')):
2115
os.remove(pjoin(match, 'results.dat'))
2118
misc.compile(['gensym'], cwd=Pdir)
2119
if not os.path.exists(pjoin(Pdir, 'gensym')):
2120
raise MadEventError, 'Error make gensym not successful'
2123
p = misc.Popen(['./gensym'], stdin=subprocess.PIPE,
2124
stdout=subprocess.PIPE,
2125
stderr=subprocess.STDOUT, cwd=Pdir)
2126
sym_input = "%(points)d %(iterations)d %(accuracy)f \n" % self.opts
2127
(stdout, stderr) = p.communicate(sym_input)
2128
if os.path.exists(pjoin(self.me_dir,'error')):
2129
files.mv(pjoin(self.me_dir,'error'), pjoin(Pdir,'ajob.no_ps.log'))
2130
P_zero_result.append(subdir)
2133
if not os.path.exists(pjoin(Pdir, 'ajob1')) or p.returncode:
2134
logger.critical(stdout)
2135
raise MadEventError, 'Error gensym run not successful'
2138
misc.compile(['madevent'], cwd=Pdir)
2140
alljobs = glob.glob(pjoin(Pdir,'ajob*'))
2141
self.total_jobs += len(alljobs)
2142
for i, job in enumerate(alljobs):
2143
job = os.path.basename(job)
2144
self.launch_job('%s' % job, cwd=Pdir, remaining=(len(alljobs)-i-1),
2145
run_type='survey on %s (%s/%s)' % (subdir,nb_proc+1,len(subproc)))
2146
if os.path.exists(pjoin(self.me_dir,'error')):
2147
self.monitor(html=True)
2148
raise MadEventError, 'Error detected Stop running: %s' % \
2149
open(pjoin(self.me_dir,'error')).read()
2151
# Check if all or only some fails
2153
if len(P_zero_result) == len(subproc):
2154
raise ZeroResult, '%s' % \
2155
open(pjoin(Pdir,'ajob.no_ps.log')).read()
2157
logger.warning(''' %s SubProcesses doesn\'t have available phase-space.
2158
Please check mass spectrum.''' % ','.join(P_zero_result))
2161
self.monitor(run_type='All jobs submitted for survey', html=True)
2162
cross, error = sum_html.make_all_html_results(self)
2163
self.results.add_detail('cross', cross)
2164
self.results.add_detail('error', error)
2165
self.update_status('End survey', 'parton', makehtml=False)
2167
############################################################################
2168
def do_refine(self, line):
2169
"""Advanced commands: launch survey for the current process """
2170
devnull = open(os.devnull, 'w')
2172
args = self.split_arg(line)
2173
# Check argument's validity
2174
self.check_refine(args)
2178
max_process = args[1]
2182
# initialize / remove lhapdf mode
2183
self.configure_directory()
2185
# Update random number
2186
self.update_random()
2189
if self.cluster_mode:
2190
logger.info('Creating Jobs')
2191
self.update_status('Refine results to %s' % precision, level=None)
2194
subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
2196
for nb_proc,subdir in enumerate(subproc):
2197
subdir = subdir.strip()
2198
Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
2199
bindir = pjoin(os.path.relpath(self.dirbin, Pdir))
2201
logger.info(' %s ' % subdir)
2202
# clean previous run
2203
for match in glob.glob(pjoin(Pdir, '*ajob*')):
2204
if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
2207
proc = misc.Popen([pjoin(bindir, 'gen_ximprove')],
2209
stdin=subprocess.PIPE,
2211
proc.communicate('%s %s T\n' % (precision, max_process))
2213
if os.path.exists(pjoin(Pdir, 'ajob1')):
2214
misc.compile(['madevent'], cwd=Pdir)
2215
alljobs = glob.glob(pjoin(Pdir,'ajob*'))
2217
#remove associated results.dat (ensure to not mix with all data)
2218
Gre = re.compile("\s*j=(G[\d\.\w]+)")
2220
Gdirs = Gre.findall(open(job).read())
2222
if os.path.exists(pjoin(Pdir, Gdir, 'results.dat')):
2223
os.remove(pjoin(Pdir, Gdir,'results.dat'))
2225
nb_tot = len(alljobs)
2226
self.total_jobs += nb_tot
2227
for i, job in enumerate(alljobs):
2228
job = os.path.basename(job)
2229
self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1),
2230
run_type='Refine number %s on %s (%s/%s)' %
2231
(self.nb_refine, subdir, nb_proc+1, len(subproc)))
2232
self.monitor(run_type='All job submitted for refine number %s' % self.nb_refine,
2235
self.update_status("Combining runs", level='parton')
2237
os.remove(pjoin(Pdir, 'combine_runs.log'))
2241
bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses')))
2243
combine_runs.CombineRuns(self.me_dir)
2245
cross, error = sum_html.make_all_html_results(self)
2246
self.results.add_detail('cross', cross)
2247
self.results.add_detail('error', error)
2249
self.update_status('finish refine', 'parton', makehtml=False)
2252
############################################################################
2253
def do_combine_events(self, line):
2254
"""Advanced commands: Launch combine events"""
2256
args = self.split_arg(line)
2257
# Check argument's validity
2258
self.check_combine_events(args)
2260
self.update_status('Combining Events', level='parton')
2262
os.remove(pjoin(self.me_dir,'SubProcesses', 'combine.log'))
2265
self.cluster.launch_and_wait('../bin/internal/run_combine',
2266
cwd=pjoin(self.me_dir,'SubProcesses'),
2267
stdout=pjoin(self.me_dir,'SubProcesses', 'combine.log'))
2269
output = misc.mult_try_open(pjoin(self.me_dir,'SubProcesses','combine.log')).read()
2270
# Store the number of unweighted events for the results object
2271
pat = re.compile(r'''\s*Unweighting\s*selected\s*(\d+)\s*events''')
2273
nb_event = pat.search(output).groups()[0]
2274
except AttributeError:
2277
nb_event = pat.search(output).groups()[0]
2278
except AttributeError:
2279
logger.warning('Fail to read the number of unweighted events in the combine.log file')
2282
self.results.add_detail('nb_event', nb_event)
2286
tag = self.run_card['run_tag']
2287
# Update the banner with the pythia card
2289
self.banner = banner_mod.recover_banner(self.results, 'parton')
2290
self.banner.load_basic(self.me_dir)
2291
# Add cross-section/event information
2292
self.banner.add_generation_info(self.results.current['cross'], nb_event)
2293
if not hasattr(self, 'random_orig'): self.random_orig = 0
2294
self.banner.change_seed(self.random_orig)
2295
if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)):
2296
os.mkdir(pjoin(self.me_dir, 'Events', self.run_name))
2297
self.banner.write(pjoin(self.me_dir, 'Events', self.run_name,
2298
'%s_%s_banner.txt' % (self.run_name, tag)))
2300
misc.call(['%s/put_banner' % self.dirbin, 'events.lhe',
2301
str(self.random_orig)],
2302
cwd=pjoin(self.me_dir, 'Events'))
2303
misc.call(['%s/put_banner'% self.dirbin, 'unweighted_events.lhe',
2304
str(self.random_orig)],
2305
cwd=pjoin(self.me_dir, 'Events'))
2307
eradir = self.options['exrootanalysis_path']
2308
madir = self.options['madanalysis_path']
2309
td = self.options['td_path']
2310
if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter')) and\
2311
os.path.exists(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')):
2312
if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)):
2313
os.mkdir(pjoin(self.me_dir, 'Events', self.run_name))
2314
self.create_root_file(output='%s/unweighted_events.root' % \
2317
############################################################################
2318
def do_compute_widths(self, line):
2319
"""Require MG5 directory: Compute automatically the widths of a set
2322
warning_text = """Be carefull automatic computation of the width is
2323
ONLY valid if all three (or more) body decay are negligeable. In doubt use a
2326
logger.warning(warning_text)
2327
logger.info('In a future version of MG5 those mode will also be taken into account')
2329
args = self.split_arg(line)
2330
# check the argument and return those in a dictionary format
2331
args = self.check_compute_widths(args)
2334
files.cp(args['input'], pjoin(self.me_dir, 'Cards'))
2335
elif not args['force']:
2336
self.ask_edit_cards(['param_card.dat'], plot=False)
2338
model = args['model']
2339
self.compute_widths(model, args)
2342
def compute_widths(model, args):
2344
data = model.set_parameters_and_couplings(args['input'])
2346
# find UFO particles linked to the require names.
2348
for pid in args['particles']:
2349
particle = model.get_particle(pid)
2350
decay_info[pid] = []
2351
mass = abs(eval(str(particle.get('mass')), data).real)
2352
data = model.set_parameters_and_couplings(args['input'], scale= mass)
2353
for mode, expr in particle.partial_widths.items():
2356
tmp_mass -= abs(eval(str(p.mass), data))
2360
decay_to = [p.get('pdg_code') for p in mode]
2361
value = eval(expr,{'cmath':cmath},data).real
2362
if -1e-10 < value < 0:
2364
if -1e-5 < value < 0:
2365
logger.warning('Partial width for %s > %s negative: %s automatically set to zero' %
2366
(particle.get('name'), ' '.join([p.get('name') for p in mode]), value))
2369
raise Exception, 'Partial width for %s > %s negative: %s' % \
2370
(particle.get('name'), ' '.join([p.get('name') for p in mode]), value)
2371
decay_info[particle.get('pdg_code')].append([decay_to, value])
2373
MadEventCmd.update_width_in_param_card(decay_info, args['input'], args['output'])
2375
############################################################################
2376
def do_store_events(self, line):
2377
"""Advanced commands: Launch store events"""
2379
args = self.split_arg(line)
2380
# Check argument's validity
2381
self.check_combine_events(args)
2382
self.update_status('Storing parton level results', level='parton')
2385
tag = self.run_card['run_tag']
2386
devnull = open(os.devnull, 'w')
2388
if not os.path.exists(pjoin(self.me_dir, 'Events', run)):
2389
os.mkdir(pjoin(self.me_dir, 'Events', run))
2390
if not os.path.exists(pjoin(self.me_dir, 'HTML', run)):
2391
os.mkdir(pjoin(self.me_dir, 'HTML', run))
2393
# 1) Store overall process information
2394
input = pjoin(self.me_dir, 'SubProcesses', 'results.dat')
2395
output = pjoin(self.me_dir, 'SubProcesses', '%s_results.dat' % run)
2396
files.cp(input, output)
2398
# 2) Treat the files present in the P directory
2399
for P_path in SubProcesses.get_subP(self.me_dir):
2400
G_dir = [G for G in os.listdir(P_path) if G.startswith('G') and
2401
os.path.isdir(pjoin(P_path,G))]
2403
G_path = pjoin(P_path,G)
2404
# Remove events file (if present)
2405
if os.path.exists(pjoin(G_path, 'events.lhe')):
2406
os.remove(pjoin(G_path, 'events.lhe'))
2408
if os.path.exists(pjoin(G_path, 'results.dat')):
2409
input = pjoin(G_path, 'results.dat')
2410
output = pjoin(G_path, '%s_results.dat' % run)
2411
files.cp(input, output)
2413
if os.path.exists(pjoin(G_path, 'log.txt')):
2414
input = pjoin(G_path, 'log.txt')
2415
output = pjoin(G_path, '%s_log.txt' % run)
2416
files.mv(input, output)
2418
for name in ['ftn26']:
2419
if os.path.exists(pjoin(G_path, name)):
2420
if os.path.exists(pjoin(G_path, '%s_%s.gz'%(run,name))):
2421
os.remove(pjoin(G_path, '%s_%s.gz'%(run,name)))
2422
input = pjoin(G_path, name)
2423
output = pjoin(G_path, '%s_%s' % (run,name))
2424
files.mv(input, output)
2425
misc.call(['gzip', output], stdout=devnull,
2426
stderr=devnull, cwd=G_path)
2427
# Delete ftn25 to ensure reproducible runs
2428
if os.path.exists(pjoin(G_path, 'ftn25')):
2429
os.remove(pjoin(G_path, 'ftn25'))
2431
# 3) Update the index.html
2432
gen_crossxhtml.GenCardHTML(self.results)
2434
# 4) Move the Files present in Events directory
2435
E_path = pjoin(self.me_dir, 'Events')
2436
O_path = pjoin(self.me_dir, 'Events', run)
2438
for name in ['events.lhe', 'unweighted_events.lhe']:
2439
if os.path.exists(pjoin(E_path, name)):
2440
if os.path.exists(pjoin(O_path, '%s.gz' % name)):
2441
os.remove(pjoin(O_path, '%s.gz' % name))
2442
input = pjoin(E_path, name)
2443
output = pjoin(O_path, name)
2444
files.mv(input, output)
2445
misc.call(['gzip', output], stdout=devnull, stderr=devnull,
2447
self.update_status('End Parton', level='parton', makehtml=False)
2450
############################################################################
2451
def do_create_gridpack(self, line):
2452
"""Advanced commands: Create gridpack from present run"""
2454
self.update_status('Creating gridpack', level='parton')
2455
args = self.split_arg(line)
2456
self.check_combine_events(args)
2457
if not self.run_tag: self.run_tag = 'tag_1'
2458
os.system("sed -i.bak \"s/ *.false.*=.*GridRun/ .true. = GridRun/g\" %s/Cards/grid_card.dat" \
2460
misc.call(['./bin/internal/restore_data', self.run_name],
2462
misc.call(['./bin/internal/store4grid',
2463
self.run_name, self.run_tag],
2465
misc.call(['./bin/internal/clean'], cwd=self.me_dir)
2466
misc.call(['./bin/internal/make_gridpack'], cwd=self.me_dir)
2467
files.mv(pjoin(self.me_dir, 'gridpack.tar.gz'),
2468
pjoin(self.me_dir, '%s_gridpack.tar.gz' % self.run_name))
2469
os.system("sed -i.bak \"s/\s*.true.*=.*GridRun/ .false. = GridRun/g\" %s/Cards/grid_card.dat" \
2471
self.update_status('gridpack created', level='gridpack')
2473
############################################################################
2474
def do_pythia(self, line):
2477
# Check argument's validity
2478
args = self.split_arg(line)
2479
if '--no_default' in args:
2480
if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia_card.dat')):
2483
args.remove('--no_default')
2487
self.check_pythia(args)
2488
# the args are modify and the last arg is always the mode
2490
self.ask_pythia_run_configuration(args[-1])
2492
# Update the banner with the pythia card
2494
self.banner = banner_mod.recover_banner(self.results, 'pythia')
2496
# initialize / remove lhapdf mode
2497
self.configure_directory()
2499
pythia_src = pjoin(self.options['pythia-pgs_path'],'src')
2501
self.update_status('Running Pythia', 'pythia')
2503
os.remove(pjoin(self.me_dir,'Events','pythia.done'))
2509
pythia_log = pjoin(self.me_dir, 'Events', self.run_name , '%s_pythia.log' % tag)
2510
self.cluster.launch_and_wait('../bin/internal/run_pythia',
2511
argument= [pythia_src], stdout= pythia_log,
2512
stderr=subprocess.STDOUT,
2513
cwd=pjoin(self.me_dir,'Events'))
2515
if not os.path.exists(pjoin(self.me_dir,'Events','pythia.done')):
2516
logger.warning('Fail to produce pythia output. More info in \n %s' % pythia_log)
2519
os.remove(pjoin(self.me_dir,'Events','pythia.done'))
2521
self.to_store.append('pythia')
2523
# Find the matched cross-section
2524
if int(self.run_card['ickkw']):
2525
# read the line from the bottom of the file
2526
pythia_log = misc.BackRead(pjoin(self.me_dir,'Events', self.run_name,
2527
'%s_pythia.log' % tag))
2528
pythiare = re.compile("\s*I\s+0 All included subprocesses\s+I\s+(?P<generated>\d+)\s+(?P<tried>\d+)\s+I\s+(?P<xsec>[\d\.D\-+]+)\s+I")
2529
for line in pythia_log:
2530
info = pythiare.search(line)
2534
# Pythia cross section in mb, we want pb
2535
sigma_m = float(info.group('xsec').replace('D','E')) *1e9
2536
Nacc = int(info.group('generated'))
2537
Ntry = int(info.group('tried'))
2539
# xsec is not float - this should not happen
2540
self.results.add_detail('cross_pythia', 0)
2541
self.results.add_detail('nb_event_pythia', 0)
2542
self.results.add_detail('error_pythia', 0)
2544
self.results.add_detail('cross_pythia', sigma_m)
2545
self.results.add_detail('nb_event_pythia', Nacc)
2546
#compute pythia error
2547
error = self.results[self.run_name].return_tag(self.run_tag)['error']
2548
error_m = math.sqrt((error * Nacc/Ntry)**2 + sigma_m**2 *(1-Nacc/Ntry)/Nacc)
2549
# works both for fixed number of generated events and fixed accepted events
2550
self.results.add_detail('error_pythia', error_m)
2555
pydir = pjoin(self.options['pythia-pgs_path'], 'src')
2556
eradir = self.options['exrootanalysis_path']
2557
madir = self.options['madanalysis_path']
2558
td = self.options['td_path']
2561
self.banner.add(pjoin(self.me_dir, 'Cards','pythia_card.dat'))
2562
banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag))
2563
self.banner.write(banner_path)
2566
self.run_hep2lhe(banner_path)
2567
if int(self.run_card['ickkw']):
2568
misc.call(['gzip','-f','beforeveto.tree'],
2569
cwd=pjoin(self.me_dir,'Events'))
2570
files.mv(pjoin(self.me_dir,'Events','beforeveto.tree.gz'),
2571
pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_beforeveto.tree.gz'))
2574
self.create_plot('Pythia')
2576
if os.path.exists(pjoin(self.me_dir,'Events','pythia_events.lhe')):
2577
shutil.move(pjoin(self.me_dir,'Events','pythia_events.lhe'),
2578
pjoin(self.me_dir,'Events', self.run_name,'%s_pythia_events.lhe' % tag))
2579
os.system('gzip -f %s' % pjoin(self.me_dir,'Events', self.run_name,
2580
'%s_pythia_events.lhe' % tag))
2583
self.update_status('finish', level='pythia', makehtml=False)
2584
self.exec_cmd('pgs --no_default', postcmd=False, printcmd=False)
2585
if self.options['delphes_path']:
2586
self.exec_cmd('delphes --no_default', postcmd=False, printcmd=False)
2587
self.print_results_in_shell(self.results.current)
2589
def get_available_tag(self):
2590
"""create automatically a tag"""
2592
used_tags = [r['tag'] for r in self.results[self.run_name]]
2596
if 'tag_%s' %i not in used_tags:
2601
################################################################################
2602
def do_remove(self, line):
2603
"""Remove one/all run or only part of it"""
2605
args = self.split_arg(line)
2606
run, tag, mode = self.check_remove(args)
2607
if 'banner' in mode:
2612
# Check first if they are not a run with a name run.
2613
if os.path.exists(pjoin(self.me_dir, 'Events', 'all')):
2614
logger.warning('A run with name all exists. So we will not supress all processes.')
2616
for match in glob.glob(pjoin(self.me_dir, 'Events','*','*_banner.txt')):
2617
run = match.rsplit(os.path.sep,2)[1]
2619
self.exec_cmd('remove %s %s' % (run, ' '.join(args[1:]) ) )
2620
except self.InvalidCmd, error:
2622
pass # run already clear
2625
# Check that run exists
2626
if not os.path.exists(pjoin(self.me_dir, 'Events', run)):
2627
raise self.InvalidCmd('No run \'%s\' detected' % run)
2630
self.resuls.def_current(run)
2631
self.update_status(' Cleaning %s' % run, level=None)
2633
misc.sprint('fail to update results or html status')
2634
pass # Just ensure that html never makes crash this function
2637
# Found the file to delete
2639
to_delete = glob.glob(pjoin(self.me_dir, 'Events', run, '*'))
2640
to_delete += glob.glob(pjoin(self.me_dir, 'HTML', run, '*'))
2641
# forbid the banner to be removed
2642
to_delete = [os.path.basename(f) for f in to_delete if 'banner' not in f]
2644
to_delete = [f for f in to_delete if tag in f]
2645
if 'parton' in mode or 'all' in mode:
2647
if self.results[run][0]['tag'] != tag:
2648
raise Exception, 'dummy'
2652
nb_rm = len(to_delete)
2653
if os.path.exists(pjoin(self.me_dir, 'Events', run, 'events.lhe.gz')):
2654
to_delete.append('events.lhe.gz')
2655
if os.path.exists(pjoin(self.me_dir, 'Events', run, 'unweighted_events.lhe.gz')):
2656
to_delete.append('unweighted_events.lhe.gz')
2657
if os.path.exists(pjoin(self.me_dir, 'HTML', run,'plots_parton.html')):
2658
to_delete.append(pjoin(self.me_dir, 'HTML', run,'plots_parton.html'))
2659
if nb_rm != len(to_delete):
2660
logger.warning('Be carefull that partonic information are on the point to be removed.')
2662
pass # delete everything
2664
if 'pythia' not in mode:
2665
to_delete = [f for f in to_delete if 'pythia' not in f]
2666
if 'pgs' not in mode:
2667
to_delete = [f for f in to_delete if 'pgs' not in f]
2668
if 'delphes' not in mode:
2669
to_delete = [f for f in to_delete if 'delphes' not in f]
2670
if 'parton' not in mode:
2671
to_delete = [f for f in to_delete if 'delphes' in f
2674
if not self.force and len(to_delete):
2675
question = 'Do you want to delete the following files?\n %s' % \
2676
'\n '.join(to_delete)
2677
ans = self.ask(question, 'y', choices=['y','n'])
2682
for file2rm in to_delete:
2683
if os.path.exists(pjoin(self.me_dir, 'Events', run, file2rm)):
2685
os.remove(pjoin(self.me_dir, 'Events', run, file2rm))
2687
shutil.rmtree(pjoin(self.me_dir, 'Events', run, file2rm))
2690
os.remove(pjoin(self.me_dir, 'HTML', run, file2rm))
2692
shutil.rmtree(pjoin(self.me_dir, 'HTML', run, file2rm))
2696
# Remove file in SubProcess directory
2697
if 'all' in mode or 'channel' in mode:
2699
if tag and self.results[run][0]['tag'] != tag:
2700
raise Exception, 'dummy'
2704
to_delete = glob.glob(pjoin(self.me_dir, 'SubProcesses', '%s*' % run))
2705
to_delete += glob.glob(pjoin(self.me_dir, 'SubProcesses', '*','%s*' % run))
2706
to_delete += glob.glob(pjoin(self.me_dir, 'SubProcesses', '*','*','%s*' % run))
2708
if self.force or len(to_delete) == 0:
2711
question = 'Do you want to delete the following files?\n %s' % \
2712
'\n '.join(to_delete)
2713
ans = self.ask(question, 'y', choices=['y','n'])
2716
for file2rm in to_delete:
2719
if 'banner' in mode:
2720
to_delete = glob.glob(pjoin(self.me_dir, 'Events', run, '*'))
2724
os.remove(pjoin(self.me_dir, 'Events',run,'%s_%s_banner.txt' % (run,tag)))
2726
logger.warning('fail to remove the banner')
2727
# remove the run from the html output
2728
if run in self.results:
2729
self.results.delete_run(run, tag)
2731
elif any(['banner' not in os.path.basename(p) for p in to_delete]):
2733
raise MadGraph5Error, '''Some output still exists for this run.
2734
Please remove those output first. Do for example:
2735
remove %s all banner
2738
shutil.rmtree(pjoin(self.me_dir, 'Events',run))
2739
if run in self.results:
2740
self.results.delete_run(run)
2743
logger.info('''The banner is not removed. In order to remove it run:
2744
remove %s all banner %s''' % (run, tag and '--tag=%s ' % tag or ''))
2747
self.results.clean(mode, run, tag)
2748
self.update_status('', level='all')
2752
################################################################################
2753
def do_plot(self, line):
2754
"""Create the plot for a given run"""
2756
# Since in principle, all plot are already done automaticaly
2758
args = self.split_arg(line)
2759
# Check argument's validity
2760
self.check_plot(args)
2761
logger.info('plot for run %s' % self.run_name)
2763
self.ask_edit_cards([], args, plot=True)
2765
if any([arg in ['all','parton'] for arg in args]):
2766
filename = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe')
2767
if os.path.exists(filename+'.gz'):
2768
os.system('gunzip -f %s' % (filename+'.gz') )
2769
if os.path.exists(filename):
2770
shutil.move(filename, pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'))
2771
self.create_plot('parton')
2772
shutil.move(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), filename)
2773
os.system('gzip -f %s' % filename)
2775
logger.info('No valid files for partonic plot')
2777
if any([arg in ['all','pythia'] for arg in args]):
2778
filename = pjoin(self.me_dir, 'Events' ,self.run_name,
2779
'%s_pythia_events.lhe' % self.run_tag)
2780
if os.path.exists(filename+'.gz'):
2781
os.system('gunzip -f %s' % (filename+'.gz') )
2782
if os.path.exists(filename):
2783
shutil.move(filename, pjoin(self.me_dir, 'Events','pythia_events.lhe'))
2784
self.create_plot('Pythia')
2785
shutil.move(pjoin(self.me_dir, 'Events','pythia_events.lhe'), filename)
2786
os.system('gzip -f %s' % filename)
2788
logger.info('No valid files for pythia plot')
2791
if any([arg in ['all','pgs'] for arg in args]):
2792
filename = pjoin(self.me_dir, 'Events', self.run_name,
2793
'%s_pgs_events.lhco' % self.run_tag)
2794
if os.path.exists(filename+'.gz'):
2795
os.system('gunzip -f %s' % (filename+'.gz') )
2796
if os.path.exists(filename):
2797
self.create_plot('PGS')
2798
os.system('gzip -f %s' % filename)
2800
logger.info('No valid files for pgs plot')
2802
if any([arg in ['all','delphes'] for arg in args]):
2803
filename = pjoin(self.me_dir, 'Events', self.run_name,
2804
'%s_delphes_events.lhco' % self.run_tag)
2805
if os.path.exists(filename+'.gz'):
2806
os.system('gunzip -f %s' % (filename+'.gz') )
2807
if os.path.exists(filename):
2808
#shutil.move(filename, pjoin(self.me_dir, 'Events','delphes_events.lhco'))
2809
self.create_plot('Delphes')
2810
#shutil.move(pjoin(self.me_dir, 'Events','delphes_events.lhco'), filename)
2811
os.system('gzip -f %s' % filename)
2813
logger.info('No valid files for delphes plot')
2817
def store_result(self):
2818
""" tar the pythia results. This is done when we are quite sure that
2819
the pythia output will not be use anymore """
2822
if not self.run_name:
2827
if not self.to_store:
2830
tag = self.run_card['run_tag']
2831
if 'pythia' in self.to_store:
2832
self.update_status('Storing Pythia files of Previous run', level='pythia', error=True)
2833
os.system('mv -f %(path)s/pythia_events.hep %(path)s/%(name)s/%(tag)s_pythia_events.hep' %
2834
{'name': self.run_name, 'path' : pjoin(self.me_dir,'Events'),
2836
os.system('gzip -f %s/%s_pythia_events.hep' % (
2837
pjoin(self.me_dir,'Events',self.run_name), tag))
2838
self.to_store.remove('pythia')
2839
self.update_status('Done', level='pythia',makehtml=False,error=True)
2843
def launch_job(self,exe, cwd=None, stdout=None, argument = [], remaining=0,
2844
run_type='', mode=None, **opt):
2846
argument = [str(arg) for arg in argument]
2848
mode = self.cluster_mode
2850
# ensure that exe is executable
2851
if os.path.exists(exe) and not os.access(exe, os.X_OK):
2852
os.system('chmod +x %s ' % exe)
2854
elif (cwd and os.path.exists(pjoin(cwd, exe))) and not \
2855
os.access(pjoin(cwd, exe), os.X_OK):
2856
os.system('chmod +x %s ' % pjoin(cwd, exe))
2859
self.update_status((remaining, 1,
2860
self.total_jobs - remaining -1, run_type), level=None, force=False)
2862
#os.system('cd %s; ./%s' % (cwd,exe))
2863
status = misc.call(['./'+exe] + argument, cwd=cwd,
2864
stdout=stdout, **opt)
2865
logger.info('%s run in %f s' % (exe, time.time() -start))
2867
raise MadGraph5Error, '%s didn\'t stop properly. Stop all computation' % exe
2871
# For condor cluster, create the input/output files
2873
input_files = ['madevent','input_app.txt','symfact.dat','iproc.dat',
2874
pjoin(self.me_dir, 'SubProcesses','randinit')]
2877
#Find the correct PDF input file
2878
input_files.append(self.get_pdf_input_filename())
2880
#Find the correct ajob
2881
Gre = re.compile("\s*j=(G[\d\.\w]+)")
2886
fsock = open(pjoin(cwd,exe))
2888
output_files = Gre.findall(text)
2889
if not output_files:
2890
Ire = re.compile("for i in ([\d\.\s]*) ; do")
2891
data = Ire.findall(text)
2892
data = ' '.join(data).split()
2894
output_files.append('G%s' % nb)
2896
for G in output_files:
2897
if os.path.isdir(pjoin(cwd,G)):
2898
input_files.append(G)
2901
self.cluster.submit2(exe, stdout=stdout, cwd=cwd,
2902
input_files=input_files, output_files=output_files)
2905
self.cluster.submit(exe, stdout=stdout, cwd=cwd)
2908
self.cluster.submit(exe, stdout=stdout, cwd=cwd)
2911
############################################################################
2912
def find_madevent_mode(self):
2913
"""Find if Madevent is in Group mode or not"""
2915
# The strategy is too look in the files Source/run_configs.inc
2916
# if we found: ChanPerJob=3 then it's a group mode.
2917
file_path = pjoin(self.me_dir, 'Source', 'run_config.inc')
2918
text = open(file_path).read()
2919
if re.search(r'''s*parameter\s+\(ChanPerJob=2\)''', text, re.I+re.M):
2924
############################################################################
2925
def monitor(self, run_type='monitor', mode=None, html=False):
2926
""" monitor the progress of running job """
2928
starttime = time.time()
2930
mode = self.cluster_mode
2933
update_status = lambda idle, run, finish: \
2934
self.update_status((idle, run, finish, run_type), level=None,
2935
force=False, starttime=starttime)
2937
update_status = lambda idle, run, finish: None
2939
self.cluster.wait(self.me_dir, update_status)
2940
except Exception, error:
2943
ans = self.ask('Cluster Error detected. Do you want to clean the queue?',
2944
default = 'y', choices=['y','n'])
2948
self.cluster.remove()
2950
except KeyboardInterrupt, error:
2951
self.cluster.remove()
2956
############################################################################
2957
def configure_directory(self):
2958
""" All action require before any type of run """
2962
assert os.path.exists(pjoin(self.me_dir,'SubProcesses'))
2964
#see when the last file was modified
2965
time_mod = max([os.path.getctime(pjoin(self.me_dir,'Cards','run_card.dat')),
2966
os.path.getctime(pjoin(self.me_dir,'Cards','param_card.dat'))])
2968
if self.configured > time_mod and hasattr(self, 'random'):
2971
self.configured = time.time()
2972
self.update_status('compile directory', level=None, update_results=True)
2973
if self.options['automatic_html_opening']:
2974
misc.open_file(os.path.join(self.me_dir, 'crossx.html'))
2975
self.options['automatic_html_opening'] = False
2976
#open only once the web page
2977
# Change current working directory
2978
self.launching_dir = os.getcwd()
2980
# Check if we need the MSSM special treatment
2981
model = self.find_model_name()
2982
if model == 'mssm' or model.startswith('mssm-'):
2983
param_card = pjoin(self.me_dir, 'Cards','param_card.dat')
2984
mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat')
2985
check_param_card.convert_to_mg5card(param_card, mg5_param)
2986
check_param_card.check_valid_param_card(mg5_param)
2988
# limit the number of event to 100k
2989
self.check_nb_events()
2991
# set environment variable for lhapdf.
2992
if self.run_card['pdlabel'] == "lhapdf":
2993
os.environ['lhapdf'] = 'True'
2994
elif 'lhapdf' in os.environ.keys():
2995
del os.environ['lhapdf']
2999
if self.run_card['iseed'] != '0':
3000
self.random = int(self.run_card['iseed'])
3001
self.run_card['iseed'] = '0'
3002
# Reset seed in run_card to 0, to ensure that following runs
3003
# will be statistically independent
3004
text = open(pjoin(self.me_dir, 'Cards','run_card.dat')).read()
3005
(t,n) = re.subn(r'\d+\s*= iseed','0 = iseed',text)
3006
open(pjoin(self.me_dir, 'Cards','run_card.dat'),'w').write(t)
3007
elif os.path.exists(pjoin(self.me_dir,'SubProcesses','randinit')):
3008
for line in open(pjoin(self.me_dir,'SubProcesses','randinit')):
3009
data = line.split('=')
3010
assert len(data) ==2
3011
self.random = int(data[1])
3014
self.random = random.randint(1, 30107)
3016
if self.run_card['ickkw'] == '2':
3017
logger.info('Running with CKKW matching')
3018
self.treat_CKKW_matching()
3020
# create param_card.inc and run_card.inc
3021
self.do_treatcards('')
3024
for name in ['../bin/internal/gen_ximprove', 'all',
3025
'../bin/internal/combine_events']:
3026
misc.compile(arg=[name], cwd=os.path.join(self.me_dir, 'Source'))
3029
############################################################################
3031
############################################################################
3033
def check_dir(path, default=''):
3034
"""check if the directory exists. if so return the path otherwise the
3037
if os.path.isdir(path):
3042
############################################################################
3043
def set_run_name(self, name, tag=None, level='parton', reload_card=False):
3044
"""define the run name, the run_tag, the banner and the results."""
3046
# when are we force to change the tag new_run:previous run requiring changes
3047
upgrade_tag = {'parton': ['parton','pythia','pgs','delphes'],
3048
'pythia': ['pythia','pgs','delphes'],
3050
'delphes':['delphes'],
3055
if name == self.run_name:
3057
run_card = pjoin(self.me_dir, 'Cards','run_card.dat')
3058
self.run_card = banner_mod.RunCard(run_card)
3060
#check if we need to change the tag
3062
self.run_card['run_tag'] = tag
3064
self.results.add_run(self.run_name, self.run_card)
3066
for tag in upgrade_tag[level]:
3067
if getattr(self.results[self.run_name][-1], tag):
3068
tag = self.get_available_tag()
3069
self.run_card['run_tag'] = tag
3071
self.results.add_run(self.run_name, self.run_card)
3073
return # Nothing to do anymore
3075
# save/clean previous run
3079
self.run_name = name
3082
run_card = pjoin(self.me_dir, 'Cards','run_card.dat')
3083
self.run_card = banner_mod.RunCard(run_card)
3086
# First call for this run -> set the banner
3087
self.banner = banner_mod.recover_banner(self.results, level)
3089
self.run_card['run_tag'] = tag
3091
elif not self.run_name in self.results and level =='parton':
3092
pass # No results yet, so current tag is fine
3093
elif not self.run_name in self.results:
3094
#This is only for case when you want to trick the interface
3095
logger.warning('Trying to run data on unknown run.')
3096
self.results.add_run(name, self.run_card)
3097
self.results.update('add run %s' % name, 'all', makehtml=False)
3099
for tag in upgrade_tag[level]:
3101
if getattr(self.results[self.run_name][-1], tag):
3102
# LEVEL is already define in the last tag -> need to switch tag
3103
tag = self.get_available_tag()
3104
self.run_card['run_tag'] = tag
3108
# We can add the results to the current run
3109
tag = self.results[self.run_name][-1]['tag']
3110
self.run_card['run_tag'] = tag # ensure that run_tag is correct
3113
if name in self.results and not new_tag:
3114
self.results.def_current(self.run_name)
3116
self.results.add_run(self.run_name, self.run_card)
3118
self.run_tag = self.run_card['run_tag']
3120
# Return the tag of the previous run having the required data for this
3121
# tag/run to working wel.
3122
if level == 'parton':
3124
elif level == 'pythia':
3125
return self.results[self.run_name][0]['tag']
3127
for i in range(-1,-len(self.results[self.run_name])-1,-1):
3128
tagRun = self.results[self.run_name][i]
3130
return tagRun['tag']
3139
############################################################################
3140
def find_model_name(self):
3141
""" return the model name """
3142
if hasattr(self, 'model_name'):
3143
return self.model_name
3147
for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')):
3148
line = line.split('#')[0]
3149
#line = line.split('=')[0]
3150
if line.startswith('import') and 'model' in line:
3151
model = line.split()[2]
3153
elif line.startswith('generate'):
3154
proc.append(line.split(None,1)[1])
3155
elif line.startswith('add process'):
3156
proc.append(line.split(None,2)[2])
3163
############################################################################
3164
def check_nb_events(self):
3165
"""Find the number of event in the run_card, and check that this is not
3169
nb_event = int(self.run_card['nevents'])
3170
if nb_event > 1000000:
3171
logger.warning("Attempting to generate more than 1M events")
3172
logger.warning("Limiting number to 1M. Use multi_run for larger statistics.")
3173
path = pjoin(self.me_dir, 'Cards', 'run_card.dat')
3174
os.system(r"""perl -p -i.bak -e "s/\d+\s*=\s*nevents/1000000 = nevents/" %s""" \
3176
self.run_card['nevents'] = 1000000
3181
############################################################################
3182
def update_random(self):
3183
""" change random number"""
3186
if self.random > 30081*30081: # can't use too big random number
3187
raise MadGraph5Error,\
3188
'Random seed too large ' + str(self.random) + ' > 30081*30081'
3190
############################################################################
3191
def save_random(self):
3192
"""save random number in appropirate file"""
3194
fsock = open(pjoin(self.me_dir, 'SubProcesses','randinit'),'w')
3195
fsock.writelines('r=%s\n' % self.random)
3197
def do_quit(self, line):
3198
"""Not in help: exit """
3201
os.remove(pjoin(self.me_dir,'RunWeb'))
3207
# If nothing runs they they are no result to update
3211
self.update_status('', level=None)
3212
except Exception, error:
3214
gen_crossxhtml.GenCardHTML(self.results)
3215
return super(MadEventCmd, self).do_quit(line)
3221
############################################################################
3222
def treat_ckkw_matching(self):
3223
"""check for ckkw"""
3225
lpp1 = self.run_card['lpp1']
3226
lpp2 = self.run_card['lpp2']
3227
e1 = self.run_card['ebeam1']
3228
e2 = self.run_card['ebeam2']
3229
pd = self.run_card['pdlabel']
3230
lha = self.run_card['lhaid']
3231
xq = self.run_card['xqcut']
3232
translation = {'e1': e1, 'e2':e2, 'pd':pd,
3236
# Remove ':s from pd
3237
if pd.startswith("'"):
3239
if pd.endswith("'"):
3247
issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(lha)s-%(xq)s.dat.gz'
3249
issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(xq)s.dat.gz'
3251
issudfile = pjoin(self.webbin, issudfile % translation)
3253
issudfile = pjoin(self.me_dir, issudfile % translation)
3255
logger.info('Sudakov grid file: %s' % issudfile)
3257
# check that filepath exists
3258
if os.path.exists(issudfile):
3259
path = pjoin(self.me_dir, 'lib', 'issudgrid.dat')
3260
os.system('gunzip -fc %s > %s' % (issudfile, path))
3262
msg = 'No sudakov grid file for parameter choice. Start to generate it. This might take a while'
3264
self.update_status('GENERATE SUDAKOF GRID', level='parton')
3266
for i in range(-2,6):
3267
self.cluster.submit('%s/gensudgrid ' % self.dirbin,
3270
stdout=open(pjoin(self.me_dir, 'gensudgrid%s.log' % i,'w')))
3272
for i in range(-2,6):
3273
path = pjoin(self.me_dir, 'lib', 'issudgrid.dat')
3274
os.system('cat %s/gensudgrid%s.log >> %s' % (self.me_dir, path))
3275
os.system('gzip -fc %s > %s' % (path, issudfile))
3277
############################################################################
3278
def create_root_file(self, input='unweighted_events.lhe',
3279
output='unweighted_events.root' ):
3280
"""create the LHE root file """
3281
self.update_status('Creating root files', level='parton')
3283
eradir = self.options['exrootanalysis_path']
3285
misc.call(['%s/ExRootLHEFConverter' % eradir,
3287
cwd=pjoin(self.me_dir, 'Events'))
3289
logger.warning('fail to produce Root output [problem with ExRootAnalysis]')
3291
############################################################################
3292
def ask_run_configuration(self, mode=None):
3293
"""Ask the question when launching generate_events/multi_run"""
3295
available_mode = ['0', '1']
3297
if self.options['pythia-pgs_path']:
3298
available_mode.append('2')
3299
available_mode.append('3')
3301
if self.options['delphes_path']:
3302
available_mode.append('4')
3304
name = {'0': 'auto', '1': 'parton', '2':'pythia', '3':'pgs', '4':'delphes'}
3306
for opt in available_mode:
3309
options += [opt, tag]
3311
options.append(10+value)
3312
options.append('%s+madspin' % tag)
3314
question = """Which programs do you want to run?
3315
0 / auto : running existing card
3316
1 / parton : Madevent\n"""
3317
if '2' in available_mode:
3318
question += """ 2 / pythia : MadEvent + Pythia.
3319
3 / pgs : MadEvent + Pythia + PGS.\n"""
3320
if '4' in available_mode:
3321
question += """ 4 / delphes : MadEvent + Pythia + Delphes.\n"""
3323
question += '+10 / +madspin: adding MadSpin [before Pythia if asked]'
3327
mode = self.ask(question, '0', options)
3335
mode = str(value-10)
3336
mode = name[mode] + '+madspin'
3343
if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia_card.dat')):
3345
elif os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
3347
elif os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
3351
if os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')):
3353
logger.info('Will run in mode %s' % mode)
3356
# Now that we know in which mode we are check that all the card
3357
#exists (copy default if needed)
3359
cards = ['param_card.dat', 'run_card.dat']
3360
if mode.endswith('+madspin'):
3362
cards.append('madspin_card.dat')
3363
if mode in ['pythia', 'pgs', 'delphes']:
3364
cards.append('pythia_card.dat')
3366
cards.append('pgs_card.dat')
3367
elif mode == 'delphes':
3368
cards.append('delphes_card.dat')
3370
if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
3372
cards.append('delphes_trigger.dat')
3373
self.keep_cards(cards)
3375
self.check_param_card(pjoin(self.me_dir,'Cards','param_card.dat' ))
3379
self.ask_edit_cards(cards, mode='auto')
3381
self.ask_edit_cards(cards)
3384
############################################################################
3385
def ask_pythia_run_configuration(self, mode=None):
3386
"""Ask the question when launching pythia"""
3388
available_mode = ['0', '1', '2']
3389
if self.options['delphes_path']:
3390
available_mode.append('3')
3391
name = {'0': 'auto', '1': 'pythia', '2':'pgs', '3':'delphes'}
3392
options = available_mode + [name[val] for val in available_mode]
3393
question = """Which programs do you want to run?
3394
0 / auto : running existing card
3396
2 / pgs : Pythia + PGS\n"""
3397
if '3' in available_mode:
3398
question += """ 3 / delphes : Pythia + Delphes.\n"""
3402
mode = self.ask(question, '0', options)
3412
if os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
3414
elif os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
3418
logger.info('Will run in mode %s' % mode)
3420
# Now that we know in which mode we are check that all the card
3421
#exists (copy default if needed) remove pointless one
3422
cards = ['pythia_card.dat']
3424
cards.append('pgs_card.dat')
3425
if mode == 'delphes':
3426
cards.append('delphes_card.dat')
3428
if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
3430
cards.append('delphes_trigger.dat')
3431
self.keep_cards(cards)
3437
self.ask_edit_cards(cards, mode='auto')
3439
self.ask_edit_cards(cards)
3445
def check_param_card(self, path):
3446
"""Check that all the width are define in the param_card.
3447
If some width are set on 'Auto', call the computation tools."""
3449
pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto''',re.I)
3450
text = open(path).read()
3451
pdg = pattern.findall(text)
3453
logger.info('Computing the width set on auto in the param_card.dat')
3454
self.do_compute_widths('%s %s' % (' '.join(pdg), path))
3456
#===============================================================================
3458
#===============================================================================
3459
class MadEventCmdShell(MadEventCmd, cmd.CmdShell):
3460
"""The command line processor of MadGraph"""
3464
#===============================================================================
3465
# HELPING FUNCTION For Subprocesses
3466
#===============================================================================
3467
class SubProcesses(object):
3473
cls.name_to_pdg = {}
3476
def get_subP(me_dir):
3477
"""return the list of Subprocesses"""
3480
for line in open(pjoin(me_dir,'SubProcesses', 'subproc.mg')):
3484
if os.path.exists(pjoin(me_dir, 'SubProcesses', name)):
3485
out.append(pjoin(me_dir, 'SubProcesses', name))
3492
def get_subP_info(path):
3493
""" return the list of processes with their name"""
3499
if not os.path.exists(os.path.join(path,'processes.dat')):
3500
return SubProcesses.get_subP_info_v4(path)
3502
for line in open(os.path.join(path,'processes.dat')):
3503
main = line[:8].strip()
3504
if main == 'mirror':
3506
if line[8:].strip() == 'none':
3512
sub_proccess = line[8:]
3513
nb_sub += sub_proccess.count(',') + 1
3515
names[main] += [sub_proccess.split(',')]
3517
names[main]= [sub_proccess.split(',')]
3522
def get_subP_info_v4(path):
3523
""" return the list of processes with their name in case without grouping """
3527
path = os.path.join(path, 'auto_dsig.f')
3529
for line in open(path):
3530
if line.startswith('C Process:'):
3532
names[''][0].append(line[15:])
3539
def get_subP_ids(path):
3540
"""return the pdg codes of the particles present in the Subprocesses"""
3543
for line in open(pjoin(path, 'leshouche.inc')):
3544
if not 'IDUP' in line:
3546
particles = re.search("/([\d,-]+)/", line)
3547
all_ids.append([int(p) for p in particles.group(1).split(',')])
3551
#===============================================================================
3552
class GridPackCmd(MadEventCmd):
3553
"""The command for the gridpack --Those are not suppose to be use interactively--"""
3555
def __init__(self, me_dir = None, nb_event=0, seed=0, *completekey, **stdin):
3556
"""Initialize the command and directly run"""
3558
# Initialize properly
3560
MadEventCmd.__init__(self, me_dir, *completekey, **stdin)
3563
self.random_orig = self.random
3564
self.options['automatic_html_opening'] = False
3565
# Now it's time to run!
3566
if me_dir and nb_event and seed:
3567
self.launch(nb_event, seed)
3569
raise MadGraph5Error,\
3570
'Gridpack run failed: ' + str(me_dir) + str(nb_event) + \
3573
def launch(self, nb_event, seed):
3574
""" launch the generation for the grid """
3576
# 1) Restore the default data
3577
logger.info('generate %s events' % nb_event)
3578
self.set_run_name('GridRun_%s' % seed)
3579
self.update_status('restoring default data', level=None)
3580
misc.call([pjoin(self.me_dir,'bin','internal','restore_data'),
3584
# 2) Run the refine for the grid
3585
self.update_status('Generating Events', level=None)
3586
#misc.call([pjoin(self.me_dir,'bin','refine4grid'),
3587
# str(nb_event), '0', 'Madevent','1','GridRun_%s' % seed],
3589
self.refine4grid(nb_event)
3591
# 3) Combine the events/pythia/...
3592
self.exec_cmd('combine_events')
3593
self.exec_cmd('store_events')
3594
self.print_results_in_shell(self.results.current)
3596
def refine4grid(self, nb_event):
3597
"""Special refine for gridpack run."""
3600
precision = nb_event
3602
# initialize / remove lhapdf mode
3603
# self.configure_directory() # All this has been done before
3604
self.cluster_mode = 0 # force single machine
3606
# Store seed in randinit file, to be read by ranmar.f
3609
self.update_status('Refine results to %s' % precision, level=None)
3610
logger.info("Using random number seed offset = %s" % self.random)
3613
subproc = [P for P in os.listdir(pjoin(self.me_dir,'SubProcesses')) if
3614
P.startswith('P') and os.path.isdir(pjoin(self.me_dir,'SubProcesses', P))]
3615
devnull = open(os.devnull, 'w')
3616
for nb_proc,subdir in enumerate(subproc):
3617
subdir = subdir.strip()
3618
Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
3619
bindir = pjoin(os.path.relpath(self.dirbin, Pdir))
3621
logger.info(' %s ' % subdir)
3622
# clean previous run
3623
for match in glob.glob(pjoin(Pdir, '*ajob*')):
3624
if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
3625
os.remove(pjoin(Pdir, match))
3628
logfile = pjoin(Pdir, 'gen_ximprove.log')
3629
proc = misc.Popen([pjoin(bindir, 'gen_ximprove')],
3630
stdin=subprocess.PIPE,
3631
stdout=open(logfile,'w'),
3633
proc.communicate('%s 1 F\n' % (precision))
3635
if os.path.exists(pjoin(Pdir, 'ajob1')):
3636
alljobs = glob.glob(pjoin(Pdir,'ajob*'))
3637
nb_tot = len(alljobs)
3638
self.total_jobs += nb_tot
3639
for i, job in enumerate(alljobs):
3640
job = os.path.basename(job)
3641
self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1),
3642
run_type='Refine number %s on %s (%s/%s)' %
3643
(self.nb_refine, subdir, nb_proc+1, len(subproc)))
3644
if os.path.exists(pjoin(self.me_dir,'error')):
3645
self.monitor(html=True)
3646
raise MadEventError, \
3647
'Error detected in dir %s: %s' % \
3648
(Pdir, open(pjoin(self.me_dir,'error')).read())
3649
self.monitor(run_type='All job submitted for refine number %s' %
3652
self.update_status("Combining runs", level='parton')
3654
os.remove(pjoin(Pdir, 'combine_runs.log'))
3658
bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses')))
3659
combine_runs.CombineRuns(self.me_dir)
3662
cross, error = sum_html.make_all_html_results(self)
3663
self.results.add_detail('cross', cross)
3664
self.results.add_detail('error', error)
3667
self.update_status('finish refine', 'parton', makehtml=False)
3672
AskforEditCard = common_run.AskforEditCard