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
42
GNU_SPLITTING = ('GNU' in readline.__doc__)
46
root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
47
root_path = os.path.split(root_path)[0]
48
sys.path.insert(0, os.path.join(root_path,'bin'))
52
# Special logger for the Cmd Interface
53
logger = logging.getLogger('madgraph.stdout') # -> stdout
54
logger_stderr = logging.getLogger('madgraph.stderr') # ->stderr
58
# import from madgraph directory
59
import madgraph.interface.extended_cmd as cmd
60
import madgraph.various.banner as banner_mod
61
import madgraph.various.misc as misc
62
import madgraph.iolibs.files as files
63
import madgraph.various.cluster as cluster
64
import models.check_param_card as check_param_card
65
import madgraph.various.gen_crossxhtml as gen_crossxhtml
66
from madgraph import InvalidCmd, MadGraph5Error, MG5DIR
68
except Exception, error:
71
# import from madevent directory
72
import internal.extended_cmd as cmd
73
import internal.banner as banner_mod
74
import internal.misc as misc
75
import internal.cluster as cluster
76
import internal.check_param_card as check_param_card
77
import internal.files as files
78
from internal import InvalidCmd, MadGraph5Error
79
import internal.gen_crossxhtml as gen_crossxhtml
82
#===============================================================================
84
#===============================================================================
85
class HelpToCmd(object):
86
""" The Series of help routins in common between amcatnlo_run and
89
def help_treatcards(self):
90
logger.info("syntax: treatcards [param|run] [--output_dir=] [--param_card=] [--run_card=]")
91
logger.info("-- create the .inc files containing the cards information." )
94
logger.info("syntax: set %s argument" % "|".join(self._set_options))
95
logger.info("-- set options")
96
logger.info(" stdout_level DEBUG|INFO|WARNING|ERROR|CRITICAL")
97
logger.info(" change the default level for printed information")
98
logger.info(" timeout VALUE")
99
logger.info(" (default 20) Seconds allowed to answer questions.")
100
logger.info(" Note that pressing tab always stops the timer.")
101
logger.info(" cluster_temp_path PATH")
102
logger.info(" (default None) Allow to perform the run in PATH directory")
103
logger.info(" This allow to not run on the central disk. This is not used")
104
logger.info(" by condor cluster (since condor has it's own way to prevent it).")
107
logger.info("syntax: help [RUN] [%s] [-f]" % '|'.join(self._plot_mode))
108
logger.info("-- create the plot for the RUN (current run by default)")
109
logger.info(" at the different stage of the event generation")
110
logger.info(" Note than more than one mode can be specified in the same command.")
111
logger.info(" This require to have MadAnalysis and td require. By default")
112
logger.info(" if those programs are installed correctly, the creation")
113
logger.info(" will be performed automaticaly during the event generation.")
114
logger.info(" -f options: answer all question by default.")
116
def help_pythia(self):
117
logger.info("syntax: pythia [RUN] [--run_options]")
118
logger.info("-- run pythia on RUN (current one by default)")
119
self.run_options_help([('-f','answer all question by default'),
120
('--tag=', 'define the tag for the pythia run'),
121
('--no_default', 'not run if pythia_card not present')])
124
logger.info("syntax: pgs [RUN] [--run_options]")
125
logger.info("-- run pgs on RUN (current one by default)")
126
self.run_options_help([('-f','answer all question by default'),
127
('--tag=', 'define the tag for the pgs run'),
128
('--no_default', 'not run if pgs_card not present')])
130
def help_delphes(self):
131
logger.info("syntax: delphes [RUN] [--run_options]")
132
logger.info("-- run delphes on RUN (current one by default)")
133
self.run_options_help([('-f','answer all question by default'),
134
('--tag=', 'define the tag for the delphes run'),
135
('--no_default', 'not run if delphes_card not present')])
137
def help_decay_events(self, skip_syntax=False):
139
logger.info("syntax: decay_events [RUN]")
140
logger.info("This functionality allows for the decay of resonances")
141
logger.info("in a .lhe file, keeping track of the spin correlation effets.")
142
logger.info("BE AWARE OF THE CURRENT LIMITATIONS:")
143
logger.info(" (1) Only a succession of 2 body decay are currently allowed")
147
class CheckValidForCmd(object):
148
""" The Series of check routines in common between amcatnlo_run and
149
madevent interface"""
151
def check_set(self, args):
152
""" check the validity of the line"""
156
raise self.InvalidCmd('set needs an option and an argument')
158
if args[0] not in self._set_options + self.options.keys():
160
raise self.InvalidCmd('Possible options for set are %s' % \
163
if args[0] in ['stdout_level']:
164
if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] \
165
and not args[1].isdigit():
166
raise self.InvalidCmd('output_level needs ' + \
169
if args[0] in ['timeout']:
170
if not args[1].isdigit():
171
raise self.InvalidCmd('timeout values should be a integer')
173
def check_open(self, args):
174
""" check the validity of the line """
178
raise self.InvalidCmd('OPEN command requires exactly one argument')
180
if args[0].startswith('./'):
181
if not os.path.isfile(args[0]):
182
raise self.InvalidCmd('%s: not such file' % args[0])
185
# if special : create the path.
187
if not os.path.isfile(args[0]):
189
raise self.InvalidCmd('No MadEvent path defined. Unable to associate this name to a file')
194
if os.path.isfile(os.path.join(path,args[0])):
195
args[0] = os.path.join(path,args[0])
196
elif os.path.isfile(os.path.join(path,'Cards',args[0])):
197
args[0] = os.path.join(path,'Cards',args[0])
198
elif os.path.isfile(os.path.join(path,'HTML',args[0])):
199
args[0] = os.path.join(path,'HTML',args[0])
200
# special for card with _default define: copy the default and open it
201
elif '_card.dat' in args[0]:
202
name = args[0].replace('_card.dat','_card_default.dat')
203
if os.path.isfile(os.path.join(path,'Cards', name)):
204
files.cp(path + '/Cards/' + name, path + '/Cards/'+ args[0])
205
args[0] = os.path.join(path,'Cards', args[0])
207
raise self.InvalidCmd('No default path for this file')
208
elif not os.path.isfile(args[0]):
209
raise self.InvalidCmd('No default path for this file')
211
def check_treatcards(self, args):
212
"""check that treatcards arguments are valid
213
[param|run|all] [--output_dir=] [--param_card=] [--run_card=]
216
opt = {'output_dir':pjoin(self.me_dir,'Source'),
217
'param_card':pjoin(self.me_dir,'Cards','param_card.dat'),
218
'run_card':pjoin(self.me_dir,'Cards','run_card.dat')}
221
if arg.startswith('--') and '=' in arg:
222
key,value =arg[2:].split('=',1)
224
self.help_treatcards()
225
raise self.InvalidCmd('Invalid option for treatcards command:%s ' \
227
if key in ['param_card', 'run_card']:
228
if os.path.isfile(value):
229
card_name = self.detect_card_type(value)
231
raise self.InvalidCmd('Format for input file detected as %s while expecting %s'
234
elif os.path.isfile(pjoin(self.me_dir,value)):
235
card_name = self.detect_card_type(pjoin(self.me_dir,value))
237
raise self.InvalidCmd('Format for input file detected as %s while expecting %s'
241
raise self.InvalidCmd('No such file: %s ' % value)
242
elif key in ['output_dir']:
243
if os.path.isdir(value):
245
elif os.path.isdir(pjoin(self.me_dir,value)):
246
opt[key] = pjoin(self.me_dir, value)
248
raise self.InvalidCmd('No such directory: %s' % value)
249
elif arg in ['param','run','all']:
252
self.help_treatcards()
253
raise self.InvalidCmd('Unvalid argument %s' % arg)
257
def check_decay_events(self,args):
258
"""Check the argument for decay_events command
259
syntax: decay_events [NAME]
260
Note that other option are already remove at this point
264
if '-from_cards' in args:
265
args.remove('-from_cards')
266
opts.append('-from_cards')
270
args.insert(0, self.run_name)
271
elif self.results.lastrun:
272
args.insert(0, self.results.lastrun)
274
raise self.InvalidCmd('No run name currently defined. Please add this information.')
277
if args[0] != self.run_name:
278
self.set_run_name(args[0])
280
if self.mode == 'madevent':
282
pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe.gz'),
283
pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe')]
286
pjoin(self.me_dir,'Events',args[0], 'events.lhe.gz'),
287
pjoin(self.me_dir,'Events',args[0], 'events.lhe')]
289
for path in possible_path:
290
if os.path.exists(path):
294
raise self.InvalidCmd('No events file corresponding to %s run. ' % args[0])
295
args[0] = correct_path
300
class MadEventAlreadyRunning(InvalidCmd):
303
#===============================================================================
305
#===============================================================================
306
class CommonRunCmd(HelpToCmd, CheckValidForCmd, cmd.Cmd):
308
debug_output = 'ME5_debug'
309
helporder = ['Main commands', 'Documented commands', 'Require MG5 directory',
312
# The three options categories are treated on a different footage when a
313
# set/save configuration occur. current value are kept in self.options
314
options_configuration = {'pythia8_path': './pythia8',
315
'madanalysis_path': './MadAnalysis',
316
'pythia-pgs_path':'./pythia-pgs',
318
'delphes_path':'./Delphes',
319
'exrootanalysis_path':'./ExRootAnalysis',
320
'MCatNLO-utilities_path':'./MCatNLO-utilities',
325
'fortran_compiler':None,
327
'cluster_type': 'condor',
328
'cluster_status_update': (600, 30)}
330
options_madgraph= {'stdout_level':None}
332
options_madevent = {'automatic_html_opening':True,
334
'cluster_queue':'madgraph',
336
'cluster_temp_path':None}
340
def __init__(self, me_dir, options, *args, **opts):
343
cmd.Cmd.__init__(self, *args, **opts)
344
# Define current MadEvent directory
345
if me_dir is None and MADEVENT:
349
self.options = options
352
self.status = pjoin(self.me_dir, 'status')
353
self.error = pjoin(self.me_dir, 'error')
354
self.dirbin = pjoin(self.me_dir, 'bin', 'internal')
356
# Check that the directory is not currently running
357
if os.path.exists(pjoin(me_dir,'RunWeb')):
358
message = '''Another instance of madevent is currently running.
359
Please wait that all instance of madevent are closed. If no
360
instance is running, you can delete the file
361
%s and try again.''' % pjoin(me_dir,'RunWeb')
362
raise MadEventAlreadyRunning, message
365
fsock = open(pjoin(me_dir,'RunWeb'),'w')
373
# Load the configuration file
374
self.set_configuration()
375
self.configure_run_mode(self.options['run_mode'])
378
# Get number of initial states
379
nexternal = open(pjoin(self.me_dir,'Source','nexternal.inc')).read()
380
found = re.search("PARAMETER\s*\(NINCOMING=(\d)\)", nexternal)
381
self.ninitial = int(found.group(1))
384
############################################################################
385
def split_arg(self, line, error=False):
386
"""split argument and remove run_options"""
388
args = cmd.Cmd.split_arg(line)
390
if not arg.startswith('-'):
393
self.configure_run_mode(1)
395
self.configure_run_mode(2)
398
elif not arg.startswith('--'):
400
raise self.InvalidCmd('%s argument cannot start with - symbol' % arg)
403
elif arg.startswith('--cluster'):
404
self.configure_run_mode(1)
405
elif arg.startswith('--multicore'):
406
self.configure_run_mode(2)
407
elif arg.startswith('--nb_core'):
408
self.nb_core = int(arg.split('=',1)[1])
409
self.configure_run_mode(2)
410
elif arg.startswith('--web'):
411
self.pass_in_web_mode()
412
#self.configure_run_mode(1)
419
############################################################################
420
def do_treatcards(self, line, amcatnlo=False):
421
"""Advanced commands: create .inc files from param_card.dat/run_card.dat"""
424
if '--keepwidth' in line:
426
line = line.replace('--keepwidth', '')
427
args = self.split_arg(line)
428
mode, opt = self.check_treatcards(args)
430
if mode in ['run', 'all']:
431
if not hasattr(self, 'run_card'):
433
run_card = banner_mod.RunCardNLO(opt['run_card'])
435
run_card = banner_mod.RunCard(opt['run_card'])
437
run_card = self.run_card
438
run_card.write_include_file(pjoin(opt['output_dir'],'run_card.inc'))
440
if mode in ['param', 'all']:
441
if os.path.exists(pjoin(self.me_dir, 'Source', 'MODEL', 'mp_coupl.inc')):
442
param_card = check_param_card.ParamCardMP(opt['param_card'])
444
param_card = check_param_card.ParamCard(opt['param_card'])
445
outfile = pjoin(opt['output_dir'], 'param_card.inc')
446
ident_card = pjoin(self.me_dir,'Cards','ident_card.dat')
447
if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')):
448
default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')
449
elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')):
450
default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
451
elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')):
452
fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w')
457
subprocess.call(['python', 'write_param_card.py'],
458
cwd=pjoin(self.me_dir,'bin','internal','ufomodel'))
459
default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
461
if amcatnlo and not keepwidth:
462
# force particle in final states to have zero width
463
pids = self.get_pid_final_states()
464
# check those which are charged under qcd
465
if not MADEVENT and pjoin(self.me_dir,'bin') not in sys.path:
466
sys.path.append(pjoin(self.me_dir,'bin'))
467
import internal.ufomodel as ufomodel
468
zero = ufomodel.parameters.ZERO
469
no_width = [p for p in ufomodel.all_particles
470
if (str(p.pdg_code) in pids or str(-p.pdg_code) in pids)
471
and p.color != 1 and p.width != zero]
474
for part in no_width:
475
if abs(part.pdg_code) in done:
477
done.append(abs(part.pdg_code))
478
param = param_card['decay'].get((part.pdg_code,))
481
logger.info('''For gauge cancellation, the width of \'%s\' has been set to zero.'''
482
% part.name,'$MG:color:BLACK')
487
param_card.write_inc_file(outfile, ident_card, default)
490
def ask_edit_cards(self, cards, mode='fixed', plot=True):
495
return path.split('_card')[0]
496
elif path == 'delphes_trigger.dat':
499
raise Exception, 'Unknow cards name'
501
# Ask the user if he wants to edit any of the files
502
#First create the asking text
503
question = """Do you want to edit one cards (press enter to bypass editing)?\n"""
504
possible_answer = ['0', 'done']
507
for i, card_name in enumerate(cards):
508
imode = path2name(card_name)
509
possible_answer.append(i+1)
510
possible_answer.append(imode)
511
question += ' %s / %-9s : %s\n' % (i+1, imode, card_name)
514
if plot and self.options['madanalysis_path']:
515
question += ' 9 / %-9s : plot_card.dat\n' % 'plot'
516
possible_answer.append(9)
517
possible_answer.append('plot')
520
if 'param_card.dat' in cards:
521
# Add the path options
522
question += ' you can also\n'
523
question += ' - enter the path to a valid card or banner.\n'
524
question += ' - use the \'set\' command to modify a parameter directly.\n'
525
question += ' The set option works only for param_card and run_card.\n'
526
question += ' Type \'help set\' for more information on this command.\n'
528
question += ' you can also\n'
529
question += ' - enter the path to a valid card.\n'
532
while out not in ['0', 'done']:
533
out = self.ask(question, '0', possible_answer, timeout=int(1.5*self.options['timeout']),
534
path_msg='enter path', ask_class = AskforEditCard,
535
cards=cards, mode=mode)
539
def detect_card_type(path):
540
"""detect the type of the card. Return value are
553
text = open(path).read(50000)
555
logger.warning('File %s is empty' % path)
557
text = re.findall('(<MGVersion>|ParticlePropagator|<mg5proccard>|CEN_max_tracker|#TRIGGER CARD|parameter set name|muon eta coverage|QES_over_ref|MSTP|Herwig\+\+|MSTU|Begin Minpts|gridpack|ebeam1|BLOCK|DECAY|launch|madspin)', text, re.I)
558
text = [t.lower() for t in text]
559
if '<mgversion>' in text or '<mg5proccard>' in text:
561
elif 'particlepropagator' in text:
562
return 'delphes_card.dat'
563
elif 'cen_max_tracker' in text:
564
return 'delphes_card.dat'
565
elif '#trigger card' in text:
566
return 'delphes_trigger.dat'
567
elif 'parameter set name' in text:
568
return 'pgs_card.dat'
569
elif 'muon eta coverage' in text:
570
return 'pgs_card.dat'
571
elif 'mstp' in text and not 'herwig++' in text:
572
return 'pythia_card.dat'
573
elif 'begin minpts' in text:
574
return 'plot_card.dat'
575
elif ('gridpack' in text and 'ebeam1' in text) or \
576
('qes_over_ref' in text and 'ebeam1' in text):
577
return 'run_card.dat'
578
elif 'block' in text and 'decay' in text:
579
return 'param_card.dat'
580
elif 'herwig++' in text:
581
return 'shower_card.dat'
582
elif 'decay' in text and 'launch' in text and 'madspin' in text:
583
return 'madspin_card.dat'
587
############################################################################
588
def create_plot(self, mode='parton', event_path=None, output=None):
589
"""create the plot"""
591
madir = self.options['madanalysis_path']
592
tag = self.run_card['run_tag']
593
td = self.options['td_path']
595
if not madir or not td or \
596
not os.path.exists(pjoin(self.me_dir, 'Cards', 'plot_card.dat')):
599
if 'ickkw' in self.run_card and int(self.run_card['ickkw']) and \
601
self.update_status('Create matching plots for Pythia', level='pythia')
602
# recover old data if none newly created
603
if not os.path.exists(pjoin(self.me_dir,'Events','events.tree')):
604
misc.call(['gunzip', '-c', pjoin(self.me_dir,'Events',
605
self.run_name, '%s_pythia_events.tree.gz' % tag)],
606
stdout=open(pjoin(self.me_dir,'Events','events.tree'),'w')
608
files.mv(pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree'),
609
pjoin(self.me_dir,'Events','xsecs.tree'))
611
# Generate the matching plots
612
misc.call([self.dirbin+'/create_matching_plots.sh',
613
self.run_name, tag, madir],
614
stdout = os.open(os.devnull, os.O_RDWR),
615
cwd=pjoin(self.me_dir,'Events'))
618
misc.call(['gzip','-f','events.tree'],
619
cwd=pjoin(self.me_dir,'Events'))
620
files.mv(pjoin(self.me_dir,'Events','events.tree.gz'),
621
pjoin(self.me_dir,'Events',self.run_name, tag + '_pythia_events.tree.gz'))
622
files.mv(pjoin(self.me_dir,'Events','xsecs.tree'),
623
pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree'))
629
pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'),
630
pjoin(self.me_dir, 'Events', 'unweighted_events.lhe.gz'),
631
pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe'),
632
pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')]
633
for event_path in possibilities:
634
if os.path.exists(event_path):
636
output = pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html')
637
elif mode == 'Pythia':
638
event_path = pjoin(self.me_dir, 'Events','pythia_events.lhe')
639
output = pjoin(self.me_dir, 'HTML',self.run_name,
640
'plots_pythia_%s.html' % tag)
642
event_path = pjoin(self.me_dir, 'Events', self.run_name,
643
'%s_pgs_events.lhco' % tag)
644
output = pjoin(self.me_dir, 'HTML',self.run_name,
645
'plots_pgs_%s.html' % tag)
646
elif mode == 'Delphes':
647
event_path = pjoin(self.me_dir, 'Events', self.run_name,'%s_delphes_events.lhco' % tag)
648
output = pjoin(self.me_dir, 'HTML',self.run_name,
649
'plots_delphes_%s.html' % tag)
651
raise self.InvalidCmd, 'Invalid mode %s' % mode
655
if not os.path.exists(event_path):
656
if os.path.exists(event_path+'.gz'):
657
os.system('gunzip -f %s.gz ' % event_path)
659
raise self.InvalidCmd, 'Events file %s does not exits' % event_path
661
self.update_status('Creating Plots for %s level' % mode, level = mode.lower())
663
plot_dir = pjoin(self.me_dir, 'HTML', self.run_name,'plots_%s_%s' % (mode.lower(),tag))
665
if not os.path.isdir(plot_dir):
666
os.makedirs(plot_dir)
668
files.ln(pjoin(self.me_dir, 'Cards','plot_card.dat'), plot_dir, 'ma_card.dat')
671
proc = misc.Popen([os.path.join(madir, 'plot_events')],
672
stdout = open(pjoin(plot_dir, 'plot.log'),'w'),
673
stderr = subprocess.STDOUT,
674
stdin=subprocess.PIPE,
676
proc.communicate('%s\n' % event_path)
679
misc.call(['%s/plot' % self.dirbin, madir, td],
680
stdout = open(pjoin(plot_dir, 'plot.log'),'a'),
681
stderr = subprocess.STDOUT,
684
misc.call(['%s/plot_page-pl' % self.dirbin,
685
os.path.basename(plot_dir),
687
stdout = open(pjoin(plot_dir, 'plot.log'),'a'),
688
stderr = subprocess.STDOUT,
689
cwd=pjoin(self.me_dir, 'HTML', self.run_name))
690
shutil.move(pjoin(self.me_dir, 'HTML',self.run_name ,'plots.html'),
693
logger.info("Plots for %s level generated, see %s" % \
695
except OSError, error:
696
logger.error('fail to create plot: %s. Please check that MadAnalysis is correctly installed.' % error)
698
self.update_status('End Plots for %s level' % mode, level = mode.lower(),
703
def run_hep2lhe(self, banner_path = None):
704
"""Run hep2lhe on the file Events/pythia_events.hep"""
706
if not self.options['pythia-pgs_path']:
707
raise self.InvalidCmd, 'No pythia-pgs path defined'
709
pydir = pjoin(self.options['pythia-pgs_path'], 'src')
710
eradir = self.options['exrootanalysis_path']
713
if misc.is_executable(pjoin(pydir, 'hep2lhe')):
714
self.update_status('Creating Pythia LHE File', level='pythia')
715
# Write the banner to the LHE file
716
out = open(pjoin(self.me_dir,'Events','pythia_events.lhe'), 'w')
717
#out.writelines('<LesHouchesEvents version=\"1.0\">\n')
718
out.writelines('<!--\n')
719
out.writelines('# Warning! Never use this file for detector studies!\n')
720
out.writelines('-->\n<!--\n')
722
out.writelines(open(banner_path).read().replace('<LesHouchesEvents version="1.0">',''))
723
out.writelines('\n-->\n')
726
self.cluster.launch_and_wait(self.dirbin+'/run_hep2lhe',
728
cwd=pjoin(self.me_dir,'Events'))
730
logger.info('Warning! Never use this pythia lhe file for detector studies!')
732
if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHEFConverter')):
733
self.update_status('Creating Pythia LHE Root File', level='pythia')
735
misc.call([eradir+'/ExRootLHEFConverter',
737
pjoin(self.run_name, '%s_pythia_lhe_events.root' % self.run_tag)],
738
cwd=pjoin(self.me_dir,'Events'))
739
except Exception, error:
740
misc.sprint('ExRootLHEFConverter fails', str(error),
744
def store_result(self):
745
"""Dummy routine, to be overwritten by daughter classes"""
749
############################################################################
750
def do_pgs(self, line):
753
args = self.split_arg(line)
754
# Check argument's validity
755
if '--no_default' in args:
757
args.remove('--no_default')
761
# Check all arguments
762
# This might launch a gunzip in another thread. After the question
763
# This thread need to be wait for completion. (This allow to have the
764
# question right away and have the computer working in the same time)
765
# if lock is define this a locker for the completion of the thread
766
lock = self.check_pgs(args)
768
# Check that the pgs_card exists. If not copy the default
769
if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
771
logger.info('No pgs_card detected, so not run pgs')
774
files.cp(pjoin(self.me_dir, 'Cards', 'pgs_card_default.dat'),
775
pjoin(self.me_dir, 'Cards', 'pgs_card.dat'))
776
logger.info('No pgs card found. Take the default one.')
778
if not (no_default or self.force):
779
self.ask_edit_cards(['pgs_card.dat'])
781
self.update_status('prepare PGS run', level=None)
783
pgsdir = pjoin(self.options['pythia-pgs_path'], 'src')
784
eradir = self.options['exrootanalysis_path']
785
madir = self.options['madanalysis_path']
786
td = self.options['td_path']
788
# Compile pgs if not there
789
if not misc.is_executable(pjoin(pgsdir, 'pgs')):
790
logger.info('No PGS executable -- running make')
791
misc.compile(cwd=pgsdir)
793
self.update_status('Running PGS', level='pgs')
796
# Update the banner with the pgs card
797
banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, self.run_tag))
798
if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
799
self.banner.add(pjoin(self.me_dir, 'Cards','pgs_card.dat'))
800
self.banner.write(banner_path)
802
open(banner_path, 'w').close()
804
########################################################################
805
# now pass the event to a detector simulator and reconstruct objects
806
########################################################################
809
# Prepare the output file with the banner
810
ff = open(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'), 'w')
811
if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
812
text = open(banner_path).read()
813
text = '#%s' % text.replace('\n','\n#')
814
dico = self.results[self.run_name].get_current_info()
815
text +='\n## Integrated weight (pb) : %.4g' % dico['cross']
816
text +='\n## Number of Event : %s\n' % dico['nb_event']
821
os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
824
pgs_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_pgs.log" % tag)
825
self.cluster.launch_and_wait('../bin/internal/run_pgs',
826
argument=[pgsdir], cwd=pjoin(self.me_dir,'Events'),
827
stdout=pgs_log, stderr=subprocess.STDOUT)
829
if not os.path.exists(pjoin(self.me_dir, 'Events', 'pgs.done')):
830
logger.error('Fail to create LHCO events')
833
os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
835
if os.path.getsize(banner_path) == os.path.getsize(pjoin(self.me_dir, 'Events','pgs_events.lhco')):
836
misc.call(['cat pgs_uncleaned_events.lhco >> pgs_events.lhco'],
837
cwd=pjoin(self.me_dir, 'Events'))
838
os.remove(pjoin(self.me_dir, 'Events', 'pgs_uncleaned_events.lhco '))
841
if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHCOlympicsConverter')):
842
self.update_status('Creating PGS Root File', level='pgs')
844
misc.call([eradir+'/ExRootLHCOlympicsConverter',
845
'pgs_events.lhco',pjoin('%s/%s_pgs_events.root' % (self.run_name, tag))],
846
cwd=pjoin(self.me_dir, 'Events'))
848
logger.warning('fail to produce Root output [problem with ExRootAnalysis')
849
if os.path.exists(pjoin(self.me_dir, 'Events', 'pgs_events.lhco')):
851
files.mv(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'),
852
pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag))
853
self.create_plot('PGS')
854
misc.call(['gzip','-f', pjoin(self.me_dir, 'Events',
855
self.run_name, '%s_pgs_events.lhco' % tag)])
857
self.update_status('finish', level='pgs', makehtml=False)
859
############################################################################
860
def do_delphes(self, line):
861
""" run delphes and make associate root file/plot """
863
args = self.split_arg(line)
864
# Check argument's validity
865
if '--no_default' in args:
867
args.remove('--no_default')
870
# Check all arguments
871
# This might launch a gunzip in another thread. After the question
872
# This thread need to be wait for completion. (This allow to have the
873
# question right away and have the computer working in the same time)
874
# if lock is define this a locker for the completion of the thread
875
lock = self.check_delphes(args)
876
self.update_status('prepare delphes run', level=None)
879
if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
881
prog = '../bin/internal/run_delphes'
884
prog = '../bin/internal/run_delphes3'
886
# Check that the delphes_card exists. If not copy the default and
887
# ask for edition of the card.
888
if not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
890
logger.info('No delphes_card detected, so not run Delphes')
893
files.cp(pjoin(self.me_dir, 'Cards', 'delphes_card_default.dat'),
894
pjoin(self.me_dir, 'Cards', 'delphes_card.dat'))
895
logger.info('No delphes card found. Take the default one.')
896
if not delphes3 and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')):
897
files.cp(pjoin(self.me_dir, 'Cards', 'delphes_trigger_default.dat'),
898
pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat'))
899
if not (no_default or self.force):
901
self.ask_edit_cards(['delphes_card.dat'], args)
903
self.ask_edit_cards(['delphes_card.dat', 'delphes_trigger.dat'], args)
905
self.update_status('Running Delphes', level=None)
906
# Wait that the gunzip of the files is finished (if any)
912
delphes_dir = self.options['delphes_path']
914
if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
915
self.banner.add(pjoin(self.me_dir, 'Cards','delphes_card.dat'))
917
self.banner.add(pjoin(self.me_dir, 'Cards','delphes_trigger.dat'))
918
self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)))
920
cross = self.results[self.run_name].get_current_info()['cross']
922
delphes_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_delphes.log" % tag)
923
self.cluster.launch_and_wait(prog,
924
argument= [delphes_dir, self.run_name, tag, str(cross)],
925
stdout=delphes_log, stderr=subprocess.STDOUT,
926
cwd=pjoin(self.me_dir,'Events'))
928
if not os.path.exists(pjoin(self.me_dir, 'Events',
929
self.run_name, '%s_delphes_events.lhco' % tag)):
930
logger.error('Fail to create LHCO events from DELPHES')
933
if os.path.exists(pjoin(self.me_dir,'Events','delphes.root')):
934
source = pjoin(self.me_dir,'Events','delphes.root')
935
target = pjoin(self.me_dir,'Events', self.run_name, "%s_delphes_events.root" % tag)
936
files.mv(source, target)
938
#eradir = self.options['exrootanalysis_path']
939
madir = self.options['madanalysis_path']
940
td = self.options['td_path']
943
self.create_plot('Delphes')
945
if os.path.exists(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)):
946
misc.call(['gzip','-f', pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)])
950
self.update_status('delphes done', level='delphes', makehtml=False)
952
############################################################################
953
def get_pid_final_states(self):
954
"""Find the pid of all particles in the final states"""
956
subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
958
nb_init = self.ninitial
959
pat = re.compile(r'''DATA \(IDUP\(I,\d+\),I=1,\d+\)/([\+\-\d,\s]*)/''', re.I)
961
text = open(pjoin(self.me_dir, 'SubProcesses', Pdir, 'born_leshouche.inc')).read()
962
group = pat.findall(text)
963
for particles in group:
964
particles = particles.split(',')
965
pids.update(set(particles[nb_init:]))
969
############################################################################
970
def get_pdf_input_filename(self):
971
"""return the name of the file which is used by the pdfset"""
973
if hasattr(self, 'pdffile') and self.pdffile:
976
for line in open(pjoin(self.me_dir,'Source','PDF','pdf_list.txt')):
980
if data[1].lower() == self.run_card['pdlabel'].lower():
981
self.pdffile = pjoin(self.me_dir, 'lib', 'Pdfdata', data[2])
984
# possible when using lhapdf
985
self.pdffile = subprocess.Popen('%s --pdfsets-path' % self.options['lhapdf'],
986
shell = True, stdout = subprocess.PIPE).stdout.read().strip()
987
#self.pdffile = pjoin(self.me_dir, 'lib', 'PDFsets')
993
############################################################################
994
def do_open(self, line):
995
"""Open a text file/ eps file / html file"""
997
args = self.split_arg(line)
998
# Check Argument validity and modify argument to be the real path
999
self.check_open(args)
1002
misc.open_file(file_path)
1004
############################################################################
1005
def do_set(self, line, log=True):
1006
"""Set an option, which will be default for coming generations/outputs
1008
# cmd calls automaticaly post_set after this command.
1011
args = self.split_arg(line)
1012
# Check the validity of the arguments
1013
self.check_set(args)
1014
# Check if we need to save this in the option file
1015
if args[0] in self.options_configuration and '--no_save' not in args:
1016
self.do_save('options --auto')
1018
if args[0] == "stdout_level":
1019
if args[1].isdigit():
1020
logging.root.setLevel(int(args[1]))
1021
logging.getLogger('madgraph').setLevel(int(args[1]))
1023
logging.root.setLevel(eval('logging.' + args[1]))
1024
logging.getLogger('madgraph').setLevel(eval('logging.' + args[1]))
1025
if log: logger.info('set output information to level: %s' % args[1])
1026
elif args[0] == "fortran_compiler":
1027
if args[1] == 'None':
1029
self.options['fortran_compiler'] = args[1]
1030
current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'))
1031
if current != args[1] and args[1] != None:
1032
misc.mod_compilator(self.me_dir, args[1], current)
1033
elif args[0] == "run_mode":
1034
if not args[1] in [0,1,2,'0','1','2']:
1035
raise self.InvalidCmd, 'run_mode should be 0, 1 or 2.'
1036
self.cluster_mode = int(args[1])
1037
self.options['run_mode'] = self.cluster_mode
1038
elif args[0] in ['cluster_type', 'cluster_queue', 'cluster_temp_path']:
1039
if args[1] == 'None':
1041
self.options[args[0]] = args[1]
1043
self.cluster = cluster.from_name[opt['cluster_type']](\
1044
opt['cluster_queue'], opt['cluster_temp_path'])
1045
elif args[0] == 'nb_core':
1046
if args[1] == 'None':
1047
import multiprocessing
1048
self.nb_core = multiprocessing.cpu_count()
1049
self.options['nb_core'] = self.nb_core
1051
if not args[1].isdigit():
1052
raise self.InvalidCmd('nb_core should be a positive number')
1053
self.nb_core = int(args[1])
1054
self.options['nb_core'] = self.nb_core
1055
elif args[0] == 'timeout':
1056
self.options[args[0]] = int(args[1])
1057
elif args[0] == 'cluster_status_update':
1059
data = ' '.join([a for a in args[1:] if not a.startswith('-')])
1060
data = data.replace('(','').replace(')','').replace(',',' ').split()
1061
first, second = data[:2]
1063
first, second = args[1:3]
1065
self.options[args[0]] = (int(first), int(second))
1066
elif args[0] in self.options:
1067
if args[1] in ['None','True','False']:
1068
self.options[args[0]] = eval(args[1])
1069
elif args[0].endswith('path'):
1070
if os.path.exists(args[1]):
1071
self.options[args[0]] = args[1]
1072
elif os.path.exists(pjoin(self.me_dir, args[1])):
1073
self.options[args[0]] = pjoin(self.me_dir, args[1])
1075
raise self.InvalidCmd('Not a valid path: keep previous value: \'%s\'' % self.options[args[0]])
1077
self.options[args[0]] = args[1]
1079
def configure_run_mode(self, run_mode):
1080
"""change the way to submit job 0: single core, 1: cluster, 2: multicore"""
1082
self.cluster_mode = run_mode
1085
if not self.nb_core:
1086
import multiprocessing
1087
self.nb_core = multiprocessing.cpu_count()
1088
nb_core =self.nb_core
1092
if run_mode in [0, 2]:
1093
self.cluster = cluster.MultiCore(nb_core,
1094
cluster_temp_path=self.options['cluster_temp_path'])
1096
if self.cluster_mode == 1:
1098
cluster_name = opt['cluster_type']
1099
self.cluster = cluster.from_name[cluster_name](**opt)
1101
def add_error_log_in_html(self, errortype=None):
1102
"""If a ME run is currently running add a link in the html output"""
1104
# Be very carefull to not raise any error here (the traceback
1105
#will be modify in that case.)
1106
if hasattr(self, 'results') and hasattr(self.results, 'current') and\
1107
self.results.current and 'run_name' in self.results.current and \
1108
hasattr(self, 'me_dir'):
1109
name = self.results.current['run_name']
1110
tag = self.results.current['tag']
1111
self.debug_output = pjoin(self.me_dir, '%s_%s_debug.log' % (name,tag))
1113
self.results.current.debug = errortype
1115
self.results.current.debug = self.debug_output
1118
#Force class default
1119
self.debug_output = CommonRunCmd.debug_output
1120
if os.path.exists('ME5_debug') and not 'ME5_debug' in self.debug_output:
1121
os.remove('ME5_debug')
1122
if not 'ME5_debug' in self.debug_output:
1123
os.system('ln -s %s ME5_debug &> /dev/null' % self.debug_output)
1128
def update_status(self, status, level, makehtml=True, force=True,
1129
error=False, starttime = None, update_results=True):
1130
""" update the index status """
1132
if makehtml and not force:
1133
if hasattr(self, 'next_update') and time.time() < self.next_update:
1136
self.next_update = time.time() + 3
1138
if isinstance(status, str):
1139
if '<br>' not in status:
1142
running_time = misc.format_timer(time.time()-starttime)
1143
logger.info(' Idle: %s, Running: %s, Completed: %s [ %s ]' % \
1144
(status[0], status[1], status[2], running_time))
1146
logger.info(' Idle: %s, Running: %s, Completed: %s' % status[:3])
1149
self.results.update(status, level, makehtml=makehtml, error=error)
1152
############################################################################
1153
def keep_cards(self, need_card=[]):
1154
"""Ask the question when launching generate_events/multi_run"""
1156
check_card = ['pythia_card.dat', 'pgs_card.dat','delphes_card.dat',
1157
'delphes_trigger.dat', 'madspin_card.dat', 'shower_card.dat']
1159
cards_path = pjoin(self.me_dir,'Cards')
1160
for card in check_card:
1161
if card not in need_card:
1162
if os.path.exists(pjoin(cards_path, card)):
1163
os.remove(pjoin(cards_path, card))
1165
if not os.path.exists(pjoin(cards_path, card)):
1166
default = card.replace('.dat', '_default.dat')
1167
files.cp(pjoin(cards_path, default),pjoin(cards_path, card))
1169
############################################################################
1170
def set_configuration(self, config_path=None, final=True, initdir=None, amcatnlo=False):
1171
""" assign all configuration variable from file
1172
./Cards/mg5_configuration.txt. assign to default if not define """
1174
if not hasattr(self, 'options') or not self.options:
1175
self.options = dict(self.options_configuration)
1176
self.options.update(self.options_madgraph)
1177
self.options.update(self.options_madevent)
1180
if os.environ.has_key('MADGRAPH_BASE'):
1181
config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt')
1182
self.set_configuration(config_path=config_path, final=final)
1184
if 'HOME' in os.environ:
1185
config_path = pjoin(os.environ['HOME'],'.mg5',
1186
'mg5_configuration.txt')
1187
if os.path.exists(config_path):
1188
self.set_configuration(config_path=config_path, final=False)
1190
me5_config = pjoin(self.me_dir, 'Cards', 'amcatnlo_configuration.txt')
1192
me5_config = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1193
self.set_configuration(config_path=me5_config, final=False, initdir=self.me_dir)
1195
if self.options.has_key('mg5_path'):
1196
MG5DIR = self.options['mg5_path']
1197
config_file = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1198
self.set_configuration(config_path=config_file, final=False,initdir=MG5DIR)
1199
return self.set_configuration(config_path=me5_config, final=final,initdir=self.me_dir)
1201
config_file = open(config_path)
1203
# read the file and extract information
1204
logger.info('load configuration from %s ' % config_file.name)
1205
for line in config_file:
1207
line = line.split('#',1)[0]
1208
line = line.replace('\n','').replace('\r\n','')
1210
name, value = line.split('=')
1215
value = value.strip()
1216
if name.endswith('_path'):
1218
if os.path.isdir(path):
1219
self.options[name] = os.path.realpath(path)
1223
path = pjoin(initdir, value)
1224
if os.path.isdir(path):
1225
self.options[name] = os.path.realpath(path)
1228
self.options[name] = value
1229
if value.lower() == "none":
1230
self.options[name] = None
1233
return self.options # the return is usefull for unittest
1236
# Treat each expected input
1237
# delphes/pythia/... path
1238
for key in self.options:
1239
# Final cross check for the path
1240
if key.endswith('path'):
1241
path = self.options[key]
1244
if os.path.isdir(path):
1245
self.options[key] = os.path.realpath(path)
1247
path = pjoin(self.me_dir, self.options[key])
1248
if os.path.isdir(path):
1249
self.options[key] = os.path.realpath(path)
1251
elif self.options.has_key('mg5_path') and self.options['mg5_path']:
1252
path = pjoin(self.options['mg5_path'], self.options[key])
1253
if os.path.isdir(path):
1254
self.options[key] = os.path.realpath(path)
1256
self.options[key] = None
1257
elif key.startswith('cluster'):
1259
elif key == 'automatic_html_opening':
1260
if self.options[key] in ['False', 'True']:
1261
self.options[key] =eval(self.options[key])
1262
elif key not in ['text_editor','eps_viewer','web_browser','stdout_level']:
1263
# Default: try to set parameter
1265
self.do_set("%s %s --no_save" % (key, self.options[key]), log=False)
1266
except self.InvalidCmd:
1267
logger.warning("Option %s from config file not understood" \
1270
# Configure the way to open a file:
1271
misc.open_file.configure(self.options)
1276
def find_available_run_name(me_dir):
1277
""" find a valid run_name for the current job """
1280
data = [int(s[4:6]) for s in os.listdir(pjoin(me_dir,'Events')) if
1281
s.startswith('run_') and len(s)>5 and s[4:6].isdigit()]
1282
return name % (max(data+[0])+1)
1285
############################################################################
1286
def do_decay_events(self,line):
1287
"""Require MG5 directory: decay events with spin correlations
1290
if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')):
1293
# First need to load MadSpin
1295
# Check that MG5 directory is present .
1296
if MADEVENT and not self.options['mg5_path']:
1297
raise self.InvalidCmd, '''The module decay_events requires that MG5 is installed on the system.
1298
You can install it and set its path in ./Cards/me5_configuration.txt'''
1300
sys.path.append(self.options['mg5_path'])
1302
import MadSpin.decay as decay
1303
import MadSpin.interface_madspin as interface_madspin
1305
raise self.ConfigurationError, '''Can\'t load MadSpin
1306
The variable mg5_path might not be correctly configured.'''
1308
self.update_status('Running MadSpin', level='madspin')
1309
if not '-from_cards' in line:
1310
self.keep_cards(['madspin_card.dat'])
1311
self.ask_edit_cards(['madspin_card.dat'], 'fixed', plot=False)
1312
self.help_decay_events(skip_syntax=True)
1314
# load the name of the event file
1315
args = self.split_arg(line)
1316
self.check_decay_events(args)
1317
# args now alway content the path to the valid files
1318
madspin_cmd = interface_madspin.MadSpinInterface(args[0])
1321
path = pjoin(self.me_dir, 'Cards', 'madspin_card.dat')
1322
madspin_cmd.import_command_file(path)
1324
# create a new run_name directory for this output
1326
while os.path.exists(pjoin(self.me_dir,'Events', '%s_decayed_%i' % (self.run_name,i))):
1328
new_run = '%s_decayed_%i' % (self.run_name,i)
1329
evt_dir = pjoin(self.me_dir, 'Events')
1331
os.mkdir(pjoin(evt_dir, new_run))
1332
current_file = args[0].replace('.lhe', '_decayed.lhe')
1333
new_file = pjoin(evt_dir, new_run, os.path.basename(args[0]))
1334
if not os.path.exists(current_file):
1335
if os.path.exists(current_file+'.gz'):
1336
current_file += '.gz'
1339
logger.error('MadSpin fails to create any decayed file.')
1342
files.mv(current_file, new_file)
1343
logger.info("The decayed event file has been moved to the following location: ")
1344
logger.info(new_file)
1346
if hasattr(self, 'results'):
1347
nb_event = self.results.current['nb_event']
1348
cross = self.results.current['cross']
1349
error = self.results.current['error']
1350
self.results.add_run( new_run, self.run_card)
1351
self.results.add_detail('nb_event', nb_event)
1352
self.results.add_detail('cross', cross * madspin_cmd.branching_ratio)
1353
self.results.add_detail('error', error * madspin_cmd.branching_ratio)
1354
self.run_name = new_run
1355
self.update_status('MadSpin Done', level='parton', makehtml=False)
1356
if 'unweighted' in os.path.basename(args[0]):
1357
self.create_plot('parton')
1359
def complete_decay_events(self, text, line, begidx, endidx):
1360
args = self.split_arg(line[0:begidx], error=False)
1362
return self.complete_plot(text, line, begidx, endidx)
1367
class AskforEditCard(cmd.OneLinePathCompletion):
1368
"""A class for asking a question where in addition you can have the
1369
set command define and modifying the param_card/run_card correctly"""
1371
def __init__(self, question, cards=[], mode='auto', *args, **opt):
1373
cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
1374
self.me_dir = self.mother_interface.me_dir
1375
self.run_card = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card.dat'))
1377
self.param_card = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card.dat'))
1378
except check_param_card.InvalidParamCard:
1379
logger.error('Current param_card is not valid. We are going to use the default one.')
1380
files.cp(pjoin(self.me_dir,'Cards','param_card_default.dat'),
1381
pjoin(self.me_dir,'Cards','param_card.dat'))
1382
self.param_card = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card.dat'))
1383
default_param = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card_default.dat'))
1385
self.pname2block = {}
1387
self.restricted_value = {}
1391
# Read the comment of the param_card_default to find name variable for
1392
# the param_card also check which value seems to be constrained in the
1394
for bname, block in default_param.items():
1395
for lha_id, param in block.param_dict.items():
1397
comment = param.comment
1398
# treat merge parameter
1399
if comment.strip().startswith('set of param :'):
1400
all_var = list(re.findall(r'''[^-]1\*(\w*)\b''', comment))
1401
# just the variable name as comment
1402
elif len(comment.split()) == 1:
1403
all_var = [comment.strip().lower()]
1404
# either contraction or not formatted
1406
split = comment.split()
1407
if len(split) >2 and split[1] == ':':
1409
self.restricted_value[(bname, lha_id)] = ' '.join(split[1:])
1410
elif len(split) == 2:
1411
if re.search(r'''\[[A-Z]\]eV\^''', split[1]):
1412
all_var = [comment.strip().lower()]
1414
# not recognized format
1419
if var in self.pname2block:
1420
self.pname2block[var].append((bname, lha_id))
1422
self.pname2block[var] = [(bname, lha_id)]
1425
# check for conflict with run_card
1426
for var in self.pname2block:
1427
if var in self.run_card:
1428
self.conflict.append(var)
1431
def complete_set(self, text, line, begidx, endidx):
1432
""" Complete the set command"""
1434
prev_timer = signal.alarm(0) # avoid timer if any
1437
self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1438
self.stdout.write(line)
1443
args = self.split_arg(line[0:begidx])
1445
allowed = {'category':'', 'run_card':'', 'block':'all', 'param_card':''}
1446
elif len(args) == 2:
1447
if args[1] == 'run_card':
1448
allowed = {'run_card':'default'}
1449
elif args[1] == 'param_card':
1450
allowed = {'block':'all', 'param_card':'default'}
1451
elif args[1] in self.param_card.keys():
1452
allowed = {'block':args[1]}
1453
elif args[1] == 'width':
1454
allowed = {'block': 'decay'}
1456
allowed = {'value':''}
1459
if args[1] in ['run_card', 'param_card']:
1461
if args[start] in self.param_card.keys():
1463
allowed = {'block':(args[start], args[start+1:])}
1465
allowed = {'block':args[start]}
1466
elif len(args) == start +1:
1467
allowed['value'] = ''
1470
if 'category' in allowed.keys():
1471
possibilities['category of parameter (optional)'] = \
1472
self.list_completion(text, ['run_card', 'param_card'])
1474
if 'run_card' in allowed.keys():
1475
opts = self.run_card.keys()
1476
if allowed['run_card'] == 'default':
1477
opts.append('default')
1479
possibilities['Run Card'] = self.list_completion(text, opts)
1481
if 'param_card' in allowed.keys():
1482
opts = self.pname2block.keys()
1483
if allowed['param_card'] == 'default':
1484
opts.append('default')
1485
possibilities['Param Card'] = self.list_completion(text, opts)
1487
if 'value' in allowed.keys():
1491
if args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay':
1493
possibilities['Special Value'] = self.list_completion(text, opts)
1496
if 'block' in allowed.keys():
1497
if allowed['block'] == 'all':
1498
allowed_block = [i for i in self.param_card.keys() if 'qnumbers' not in i]
1499
allowed_block.append('width')
1500
possibilities['Param Card Block' ] = \
1501
self.list_completion(text, allowed_block)
1502
elif isinstance(allowed['block'], basestring):
1503
block = self.param_card[allowed['block']].param_dict
1504
ids = [str(i[0]) for i in block
1505
if (allowed['block'], i) not in self.restricted_value]
1506
possibilities['Param Card id' ] = self.list_completion(text, ids)
1507
varname = [name for name, all_var in self.pname2block.items()
1508
if any((bname == allowed['block']
1509
for bname,lhaid in all_var))]
1510
possibilities['Param card variable'] = self.list_completion(text,
1513
block = self.param_card[allowed['block'][0]].param_dict
1514
nb = len(allowed['block'][1])
1515
ids = [str(i[nb]) for i in block if len(i) > nb and \
1516
[str(a) for a in i[:nb]] == allowed['block'][1]]
1519
if tuple([int(i) for i in allowed['block'][1]]) in block:
1521
if allowed['block'][0] == 'decay':
1523
possibilities['Special value'] = self.list_completion(text, opts)
1524
possibilities['Param Card id' ] = self.list_completion(text, ids)
1526
return self.deal_multiple_categories(possibilities)
1528
def do_set(self, line):
1529
""" edit the value of one parameter in the card"""
1531
args = self.split_arg(line.lower())
1534
logger.warning('invalid set command %s' % line)
1537
card = '' #store which card need to be modify (for name conflict)
1538
if args[0] in ['run_card', 'param_card']:
1539
if args[1] == 'default':
1540
logging.info('replace %s by the default card' % args[0])
1541
files.cp(pjoin(self.me_dir,'Cards','%s_default.dat' % args[0]),
1542
pjoin(self.me_dir,'Cards','%s.dat'% args[0]))
1548
logger.warning('invalid set command: %s' % line)
1552
if args[start] in self.run_card.keys() and card != 'param_card':
1553
if args[start+1] in self.conflict and card == '':
1554
text = 'ambiguous name (present in both param_card and run_card. Please specify'
1555
logger.warning(text)
1558
if args[start+1] == 'default':
1559
default = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card_default.dat'))
1560
if args[start] in default.keys():
1561
self.setR(args[start],default[args[start]])
1563
del self.run_card[args[start]]
1564
elif args[start+1] in ['t','.true.']:
1565
self.setR(args[start], '.true.')
1566
elif args[start+1] in ['f','.false.']:
1567
self.setR(args[start], '.false.')
1570
val = eval(args[start+1])
1573
self.setR(args[start], val)
1574
self.run_card.write(pjoin(self.me_dir,'Cards','run_card.dat'))
1576
### PARAM_CARD WITH BLOCK NAME
1577
elif (args[start] in self.param_card or args[start] == 'width') \
1578
and card != 'run_card':
1579
if args[start] == 'width':
1580
args[start] = 'decay'
1582
if args[start+1] in self.conflict and card == '':
1583
text = 'ambiguous name (present in both param_card and run_card. Please specify'
1584
logger.warning(text)
1587
if args[start+1] in self.pname2block:
1588
all_var = self.pname2block[args[start+1]]
1590
for bname, lhaid in all_var:
1591
if bname == args[start]:
1595
logger.warning('%s is not part of block "%s" but "%s". please correct.' %
1596
(args[start+1], args[start], bname))
1600
key = tuple([int(i) for i in args[start+1:-1]])
1602
logger.warning('invalid set command %s' % line)
1605
if key in self.param_card[args[start]].param_dict:
1606
if (args[start], key) in self.restricted_value:
1607
text = "Note that this parameter seems to be ignore by MG.\n"
1608
text += "MG will use instead the expression: %s\n" % \
1609
self.restricted_value[(args[start], key)]
1610
text += "You need to match this expression for external program (such pythia)."
1611
logger.warning(text)
1613
if args[-1].lower() in ['default', 'auto']:
1614
self.setP(args[start], key, args[-1])
1617
value = float(args[-1])
1619
logger.warning('Invalid input: Expected number and not \'%s\'' \
1622
self.setP(args[start], key, value)
1624
logger.warning('invalid set command %s' % line)
1626
self.param_card.write(pjoin(self.me_dir,'Cards','param_card.dat'))
1628
# PARAM_CARD NO BLOCK NAME
1629
elif args[start] in self.pname2block and card != 'run_card':
1630
all_var = self.pname2block[args[start]]
1631
for bname, lhaid in all_var:
1632
new_line = 'param_card %s %s %s' % (bname,
1633
' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
1634
self.do_set(new_line)
1635
if len(all_var) > 1:
1636
logger.warning('This variable correspond to more than one parameter in the param_card.')
1637
for bname, lhaid in all_var:
1638
logger.warning(' %s %s' % (bname, ' '.join([str(i) for i in lhaid])))
1639
logger.warning('all listed variables have been modified')
1642
logger.warning('invalid set command %s' % line)
1645
def setR(self, name, value):
1646
logger.info('modify parameter %s of the run_card.dat to %s' % (name, value))
1647
self.run_card[name] = value
1649
def setP(self, block, lhaid, value):
1650
if isinstance(value, str):
1651
value = value.lower()
1652
if value == 'default':
1653
default = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card_default.dat'))
1654
value = default[block].param_dict[lhaid].value
1656
elif value == 'auto':
1658
if block != 'decay':
1659
logger.warning('Invalid input: \'Auto\' value only valid for DECAY')
1663
value = float(value)
1665
logger.warning('Invalid input: \'%s\' not valid intput.'% value)
1667
logger.info('modify param_card information BLOCK %s with id %s set to %s' %\
1668
(block, lhaid, value))
1669
self.param_card[block].param_dict[lhaid].value = value
1673
'''help message for set'''
1675
logger.info('********************* HELP SET ***************************')
1676
logger.info("syntax: set [run_card|param_card] NAME [VALUE|default]")
1677
logger.info("syntax: set [param_card] BLOCK ID(s) [VALUE|default]")
1679
logger.info('-- Edit the param_card/run_card and replace the value of the')
1680
logger.info(' parameter by the value VALUE.')
1682
logger.info('-- Example:')
1683
logger.info(' set run_card ebeam1 4000')
1684
logger.info(' set ebeam2 4000')
1685
logger.info(' set lpp1 0')
1686
logger.info(' set ptj default')
1688
logger.info(' set param_card mass 6 175')
1689
logger.info(' set mass 25 125.3')
1690
logger.info(' set mass mh 125')
1691
logger.info(' set mh 125')
1692
logger.info(' set decay 25 0.004')
1693
logger.info(' set decay wh 0.004')
1694
logger.info(' set vmix 2 1 2.326612e-01')
1696
logger.info(' set param_card default #return all parameter to default')
1697
logger.info(' set run_card default')
1698
logger.info('********************* HELP SET ***************************')
1701
def default(self, line):
1702
"""Default action if line is not recognized"""
1706
if line == '' and self.default_value is not None:
1707
self.value = self.default_value
1708
# check if input is a file
1709
elif hasattr(self, 'do_%s' % args[0]):
1710
self.do_set(' '.join(args[1:]))
1711
elif os.path.exists(line):
1712
self.copy_file(line)
1713
self.value = 'repeat'
1714
elif line.strip() != '0' and line.strip() != 'done' and \
1715
str(line) != 'EOF' and line.strip() in self.allow_arg:
1716
self.open_file(line)
1717
self.value = 'repeat'
1725
def copy_file(self, path):
1726
"""detect the type of the file and overwritte the current file"""
1728
card_name = CommonRunCmd.detect_card_type(path)
1730
if card_name == 'unknown':
1731
logger.warning('Fail to determine the type of the file. Not copied')
1732
if card_name != 'banner':
1733
logger.info('copy %s as %s' % (path, card_name))
1734
files.cp(path, pjoin(self.mother_interface.me_dir, 'Cards', card_name))
1735
elif card_name == 'banner':
1736
banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False)
1737
logger.info('Splitting the banner in it\'s component')
1738
if not self.mode == 'auto':
1739
self.mother_interface.keep_cards(self.cards)
1741
def open_file(self, answer):
1743
me_dir = self.mother_interface.me_dir
1744
if answer.isdigit():
1748
answer = self.cards[int(answer)-1]
1749
if not '.dat' in answer:
1750
if answer != 'trigger':
1751
path = pjoin(me_dir,'Cards','%s_card.dat' % answer)
1753
path = pjoin(me_dir,'Cards','delphes_trigger.dat')
1755
path = pjoin(me_dir, 'Cards', answer)
1756
self.mother_interface.exec_cmd('open %s' % path)