~maddevelopers/mg5amcnlo/WWW5_caching

« back to all changes in this revision

Viewing changes to users/mardelcourt/PROC_141512/PROC_141512/bin/internal/common_run_interface.py

  • Committer: John Doe
  • Date: 2013-03-25 20:27:02 UTC
  • Revision ID: john.doe@gmail.com-20130325202702-5sk3t1r8h33ca4p4
first clean version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
#
 
3
# Copyright (c) 2011 The MadGraph Development team and Contributors
 
4
#
 
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.
 
8
#
 
9
# It is subject to the MadGraph license which should accompany this 
 
10
# distribution.
 
11
#
 
12
# For more information, please visit: http://madgraph.phys.ucl.ac.be
 
13
#
 
14
################################################################################
 
15
"""A user friendly command line interface to access MadGraph features.
 
16
   Uses the cmd package for command interpretation and tab completion.
 
17
"""
 
18
from __future__ import division
 
19
 
 
20
import atexit
 
21
import cmath
 
22
import cmd
 
23
import glob
 
24
import logging
 
25
import math
 
26
import optparse
 
27
import os
 
28
import pydoc
 
29
import random
 
30
import re
 
31
import shutil
 
32
import signal
 
33
import stat
 
34
import subprocess
 
35
import sys
 
36
import time
 
37
import traceback
 
38
 
 
39
 
 
40
try:
 
41
    import readline
 
42
    GNU_SPLITTING = ('GNU' in readline.__doc__)
 
43
except:
 
44
    GNU_SPLITTING = True
 
45
 
 
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'))
 
49
 
 
50
# usefull shortcut
 
51
pjoin = os.path.join
 
52
# Special logger for the Cmd Interface
 
53
logger = logging.getLogger('madgraph.stdout') # -> stdout
 
54
logger_stderr = logging.getLogger('madgraph.stderr') # ->stderr
 
55
 
 
56
 
 
57
try:
 
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
 
67
    MADEVENT=False    
 
68
except Exception, error:
 
69
    if __debug__:
 
70
        print 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
 
80
    MADEVENT=True
 
81
 
 
82
#===============================================================================
 
83
# HelpToCmd
 
84
#===============================================================================
 
85
class HelpToCmd(object):
 
86
    """ The Series of help routins in common between amcatnlo_run and 
 
87
    madevent interface"""
 
88
 
 
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." )
 
92
 
 
93
    def help_set(self):
 
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).")
 
105
 
 
106
    def help_plot(self):
 
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.")
 
115
        
 
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')])        
 
122
                
 
123
    def help_pgs(self):
 
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')]) 
 
129
 
 
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')]) 
 
136
    
 
137
    def help_decay_events(self, skip_syntax=False):
 
138
        if not skip_syntax:
 
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")
 
144
 
 
145
 
 
146
 
 
147
class CheckValidForCmd(object):
 
148
    """ The Series of check routines in common between amcatnlo_run and 
 
149
    madevent interface"""
 
150
 
 
151
    def check_set(self, args):
 
152
        """ check the validity of the line"""
 
153
        
 
154
        if len(args) < 2:
 
155
            self.help_set()
 
156
            raise self.InvalidCmd('set needs an option and an argument')
 
157
 
 
158
        if args[0] not in self._set_options + self.options.keys():
 
159
            self.help_set()
 
160
            raise self.InvalidCmd('Possible options for set are %s' % \
 
161
                                  self._set_options)
 
162
        
 
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 ' + \
 
167
                                      'a valid level')  
 
168
                
 
169
        if args[0] in ['timeout']:
 
170
            if not args[1].isdigit():
 
171
                raise self.InvalidCmd('timeout values should be a integer')   
 
172
            
 
173
    def check_open(self, args):
 
174
        """ check the validity of the line """
 
175
        
 
176
        if len(args) != 1:
 
177
            self.help_open()
 
178
            raise self.InvalidCmd('OPEN command requires exactly one argument')
 
179
 
 
180
        if args[0].startswith('./'):
 
181
            if not os.path.isfile(args[0]):
 
182
                raise self.InvalidCmd('%s: not such file' % args[0])
 
183
            return True
 
184
 
 
185
        # if special : create the path.
 
186
        if not self.me_dir:
 
187
            if not os.path.isfile(args[0]):
 
188
                self.help_open()
 
189
                raise self.InvalidCmd('No MadEvent path defined. Unable to associate this name to a file')
 
190
            else:
 
191
                return True
 
192
            
 
193
        path = self.me_dir
 
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])
 
206
            else:
 
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') 
 
210
    
 
211
    def check_treatcards(self, args):
 
212
        """check that treatcards arguments are valid
 
213
           [param|run|all] [--output_dir=] [--param_card=] [--run_card=]
 
214
        """
 
215
        
 
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')}
 
219
        mode = 'all'
 
220
        for arg in args:
 
221
            if arg.startswith('--') and '=' in arg:
 
222
                key,value =arg[2:].split('=',1)
 
223
                if not key in opt:
 
224
                    self.help_treatcards()
 
225
                    raise self.InvalidCmd('Invalid option for treatcards command:%s ' \
 
226
                                          % key)
 
227
                if key in ['param_card', 'run_card']:
 
228
                    if os.path.isfile(value):
 
229
                        card_name = self.detect_card_type(value)
 
230
                        if card_name != key:
 
231
                            raise self.InvalidCmd('Format for input file detected as %s while expecting %s' 
 
232
                                                  % (card_name, key))
 
233
                        opt[key] = value
 
234
                    elif os.path.isfile(pjoin(self.me_dir,value)):
 
235
                        card_name = self.detect_card_type(pjoin(self.me_dir,value))
 
236
                        if card_name != key:
 
237
                            raise self.InvalidCmd('Format for input file detected as %s while expecting %s' 
 
238
                                                  % (card_name, key))                        
 
239
                        opt[key] = value
 
240
                    else:
 
241
                        raise self.InvalidCmd('No such file: %s ' % value)
 
242
                elif key in ['output_dir']:
 
243
                    if os.path.isdir(value):
 
244
                        opt[key] = value
 
245
                    elif os.path.isdir(pjoin(self.me_dir,value)):
 
246
                        opt[key] = pjoin(self.me_dir, value)
 
247
                    else:
 
248
                        raise self.InvalidCmd('No such directory: %s' % value)
 
249
            elif arg in ['param','run','all']:
 
250
                mode = arg
 
251
            else:
 
252
                self.help_treatcards()
 
253
                raise self.InvalidCmd('Unvalid argument %s' % arg)
 
254
                        
 
255
        return mode, opt
 
256
    
 
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
 
261
        """
 
262
        
 
263
        opts = []
 
264
        if '-from_cards' in args:
 
265
            args.remove('-from_cards')
 
266
            opts.append('-from_cards')
 
267
        
 
268
        if len(args) == 0:
 
269
            if self.run_name:
 
270
                args.insert(0, self.run_name)
 
271
            elif self.results.lastrun:
 
272
                args.insert(0, self.results.lastrun)
 
273
            else:
 
274
                raise self.InvalidCmd('No run name currently defined. Please add this information.')
 
275
                return
 
276
 
 
277
        if args[0] != self.run_name:
 
278
            self.set_run_name(args[0])
 
279
        
 
280
        if self.mode == 'madevent':
 
281
            possible_path = [
 
282
                pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe.gz'),
 
283
                pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe')]
 
284
        else:
 
285
            possible_path = [
 
286
                           pjoin(self.me_dir,'Events',args[0], 'events.lhe.gz'),
 
287
                           pjoin(self.me_dir,'Events',args[0], 'events.lhe')]
 
288
 
 
289
        for path in possible_path:
 
290
            if os.path.exists(path):
 
291
                correct_path = path
 
292
                break
 
293
        else:
 
294
            raise self.InvalidCmd('No events file corresponding to %s run. ' % args[0])
 
295
        args[0] = correct_path
 
296
        
 
297
        args += opts
 
298
     
 
299
 
 
300
class MadEventAlreadyRunning(InvalidCmd):
 
301
    pass
 
302
 
 
303
#===============================================================================
 
304
# CommonRunCmd
 
305
#===============================================================================
 
306
class CommonRunCmd(HelpToCmd, CheckValidForCmd, cmd.Cmd):
 
307
 
 
308
    debug_output = 'ME5_debug'
 
309
    helporder = ['Main commands', 'Documented commands', 'Require MG5 directory',
 
310
                   'Advanced commands']
 
311
 
 
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',
 
317
                       'td_path':'./td',
 
318
                       'delphes_path':'./Delphes',
 
319
                       'exrootanalysis_path':'./ExRootAnalysis',
 
320
                       'MCatNLO-utilities_path':'./MCatNLO-utilities',
 
321
                       'timeout': 60,
 
322
                       'web_browser':None,
 
323
                       'eps_viewer':None,
 
324
                       'text_editor':None,
 
325
                       'fortran_compiler':None,
 
326
                       'auto_update':7,
 
327
                       'cluster_type': 'condor',
 
328
                       'cluster_status_update': (600, 30)}
 
329
    
 
330
    options_madgraph= {'stdout_level':None}
 
331
    
 
332
    options_madevent = {'automatic_html_opening':True,
 
333
                         'run_mode':2,
 
334
                         'cluster_queue':'madgraph',
 
335
                         'nb_core': None,
 
336
                         'cluster_temp_path':None}
 
337
    
 
338
 
 
339
 
 
340
    def __init__(self, me_dir, options, *args, **opts):
 
341
        """common"""
 
342
        
 
343
        cmd.Cmd.__init__(self, *args, **opts)
 
344
        # Define current MadEvent directory
 
345
        if me_dir is None and MADEVENT:
 
346
            me_dir = root_path
 
347
        
 
348
        self.me_dir = me_dir
 
349
        self.options = options  
 
350
        
 
351
        # usefull shortcut
 
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')
 
355
        
 
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
 
363
        else:
 
364
            pid = os.getpid()
 
365
            fsock = open(pjoin(me_dir,'RunWeb'),'w')
 
366
            fsock.write(`pid`)
 
367
            fsock.close()
 
368
        
 
369
        self.to_store = []
 
370
        self.run_name = None
 
371
        self.run_tag = None
 
372
        self.banner = None
 
373
        # Load the configuration file
 
374
        self.set_configuration()
 
375
        self.configure_run_mode(self.options['run_mode'])
 
376
        
 
377
        
 
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))
 
382
        
 
383
 
 
384
    ############################################################################    
 
385
    def split_arg(self, line, error=False):
 
386
        """split argument and remove run_options"""
 
387
        
 
388
        args = cmd.Cmd.split_arg(line)
 
389
        for arg in args[:]:
 
390
            if not arg.startswith('-'):
 
391
                continue
 
392
            elif arg == '-c':
 
393
                self.configure_run_mode(1)
 
394
            elif arg == '-m':
 
395
                self.configure_run_mode(2)
 
396
            elif arg == '-f':
 
397
                self.force = True
 
398
            elif not arg.startswith('--'):
 
399
                if error:
 
400
                    raise self.InvalidCmd('%s argument cannot start with - symbol' % arg)
 
401
                else:
 
402
                    continue
 
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)
 
413
            else:
 
414
                continue
 
415
            args.remove(arg)
 
416
 
 
417
        return args
 
418
    
 
419
    ############################################################################      
 
420
    def do_treatcards(self, line, amcatnlo=False):
 
421
        """Advanced commands: create .inc files from param_card.dat/run_card.dat"""
 
422
 
 
423
        keepwidth = False
 
424
        if '--keepwidth' in line:
 
425
            keepwidth = True
 
426
            line = line.replace('--keepwidth', '')
 
427
        args = self.split_arg(line)
 
428
        mode,  opt  = self.check_treatcards(args)
 
429
 
 
430
        if mode in ['run', 'all']:
 
431
            if not hasattr(self, 'run_card'):
 
432
                if amcatnlo:
 
433
                    run_card = banner_mod.RunCardNLO(opt['run_card'])
 
434
                else:
 
435
                    run_card = banner_mod.RunCard(opt['run_card'])
 
436
            else:
 
437
                run_card = self.run_card
 
438
            run_card.write_include_file(pjoin(opt['output_dir'],'run_card.inc'))
 
439
        
 
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'])
 
443
            else:
 
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')
 
453
                fsock.write(' ')
 
454
                fsock.close()
 
455
                return
 
456
            else:
 
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')
 
460
                
 
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]
 
472
 
 
473
                done = []
 
474
                for part in no_width:
 
475
                    if abs(part.pdg_code) in done:
 
476
                        continue
 
477
                    done.append(abs(part.pdg_code))
 
478
                    param = param_card['decay'].get((part.pdg_code,))
 
479
                    
 
480
                    if  param.value != 0:
 
481
                        logger.info('''For gauge cancellation, the width of \'%s\' has been set to zero.'''
 
482
                                    % part.name,'$MG:color:BLACK')
 
483
                        param.value = 0
 
484
                
 
485
                
 
486
                
 
487
            param_card.write_inc_file(outfile, ident_card, default)
 
488
 
 
489
 
 
490
    def ask_edit_cards(self, cards, mode='fixed', plot=True):
 
491
        """ """
 
492
        
 
493
        def path2name(path):
 
494
            if '_card' in path:
 
495
                return path.split('_card')[0]
 
496
            elif path == 'delphes_trigger.dat':
 
497
                return 'trigger'
 
498
            else:
 
499
                raise Exception, 'Unknow cards name'
 
500
            
 
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']
 
505
        card = {0:'done'}
 
506
        
 
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)
 
512
            card[i+1] = imode
 
513
        
 
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')
 
518
            card[9] = 'plot'        
 
519
 
 
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'
 
527
        else:
 
528
            question += ' you can also\n'
 
529
            question += '   - enter the path to a valid card.\n'
 
530
        
 
531
        out = 'to_run'
 
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)
 
536
 
 
537
            
 
538
    @staticmethod
 
539
    def detect_card_type(path):
 
540
        """detect the type of the card. Return value are
 
541
           banner
 
542
           param_card.dat
 
543
           run_card.dat
 
544
           pythia_card.dat
 
545
           plot_card.dat
 
546
           pgs_card.dat
 
547
           delphes_card.dat
 
548
           delphes_trigger.dat
 
549
           shower_card.dat
 
550
           madspin_card.dat
 
551
        """
 
552
        
 
553
        text = open(path).read(50000)
 
554
        if text == '':
 
555
            logger.warning('File %s is empty' % path)
 
556
            return 'unknown'
 
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:
 
560
            return 'banner'
 
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'
 
584
        else:
 
585
            return 'unknown'
 
586
 
 
587
    ############################################################################
 
588
    def create_plot(self, mode='parton', event_path=None, output=None):
 
589
        """create the plot""" 
 
590
 
 
591
        madir = self.options['madanalysis_path']
 
592
        tag = self.run_card['run_tag']  
 
593
        td = self.options['td_path']
 
594
 
 
595
        if not madir or not td or \
 
596
            not os.path.exists(pjoin(self.me_dir, 'Cards', 'plot_card.dat')):
 
597
            return False
 
598
 
 
599
        if 'ickkw' in self.run_card and int(self.run_card['ickkw']) and \
 
600
                mode == 'Pythia':
 
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')
 
607
                          )
 
608
                files.mv(pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree'),
 
609
                     pjoin(self.me_dir,'Events','xsecs.tree'))
 
610
                
 
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'))
 
616
 
 
617
            #Clean output
 
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'))
 
624
                        
 
625
 
 
626
        if not event_path:
 
627
            if mode == 'parton':
 
628
                possibilities=[
 
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):
 
635
                        break
 
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)                                   
 
641
            elif mode == 'PGS':
 
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) 
 
650
            else:
 
651
                raise self.InvalidCmd, 'Invalid mode %s' % mode
 
652
 
 
653
            
 
654
            
 
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)
 
658
            else:
 
659
                raise self.InvalidCmd, 'Events file %s does not exits' % event_path
 
660
        
 
661
        self.update_status('Creating Plots for %s level' % mode, level = mode.lower())
 
662
               
 
663
        plot_dir = pjoin(self.me_dir, 'HTML', self.run_name,'plots_%s_%s' % (mode.lower(),tag))
 
664
                
 
665
        if not os.path.isdir(plot_dir):
 
666
            os.makedirs(plot_dir) 
 
667
        
 
668
        files.ln(pjoin(self.me_dir, 'Cards','plot_card.dat'), plot_dir, 'ma_card.dat')
 
669
                
 
670
        try:
 
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,
 
675
                            cwd=plot_dir)
 
676
            proc.communicate('%s\n' % event_path)
 
677
            del proc
 
678
            #proc.wait()
 
679
            misc.call(['%s/plot' % self.dirbin, madir, td],
 
680
                            stdout = open(pjoin(plot_dir, 'plot.log'),'a'),
 
681
                            stderr = subprocess.STDOUT,
 
682
                            cwd=plot_dir)
 
683
    
 
684
            misc.call(['%s/plot_page-pl' % self.dirbin, 
 
685
                                os.path.basename(plot_dir),
 
686
                                mode],
 
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'),
 
691
                                                                         output)
 
692
 
 
693
            logger.info("Plots for %s level generated, see %s" % \
 
694
                         (mode, output))
 
695
        except OSError, error:
 
696
            logger.error('fail to create plot: %s. Please check that MadAnalysis is correctly installed.' % error)
 
697
        
 
698
        self.update_status('End Plots for %s level' % mode, level = mode.lower(),
 
699
                                                                 makehtml=False)
 
700
        
 
701
        return True   
 
702
 
 
703
    def run_hep2lhe(self, banner_path = None):
 
704
        """Run hep2lhe on the file Events/pythia_events.hep"""
 
705
 
 
706
        if not self.options['pythia-pgs_path']:
 
707
            raise self.InvalidCmd, 'No pythia-pgs path defined'
 
708
            
 
709
        pydir = pjoin(self.options['pythia-pgs_path'], 'src')
 
710
        eradir = self.options['exrootanalysis_path']
 
711
 
 
712
        # Creating LHE file
 
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')
 
721
            if banner_path:
 
722
                out.writelines(open(banner_path).read().replace('<LesHouchesEvents version="1.0">',''))
 
723
            out.writelines('\n-->\n')
 
724
            out.close()
 
725
            
 
726
            self.cluster.launch_and_wait(self.dirbin+'/run_hep2lhe', 
 
727
                                         argument= [pydir],
 
728
                                        cwd=pjoin(self.me_dir,'Events'))
 
729
 
 
730
            logger.info('Warning! Never use this pythia lhe file for detector studies!')
 
731
            # Creating ROOT file
 
732
            if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHEFConverter')):
 
733
                self.update_status('Creating Pythia LHE Root File', level='pythia')
 
734
                try:
 
735
                    misc.call([eradir+'/ExRootLHEFConverter', 
 
736
                             'pythia_events.lhe', 
 
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), 
 
741
                                                                     log=logger)
 
742
                    pass
 
743
 
 
744
    def store_result(self):
 
745
        """Dummy routine, to be overwritten by daughter classes"""
 
746
 
 
747
        pass
 
748
 
 
749
    ############################################################################      
 
750
    def do_pgs(self, line):
 
751
        """launch pgs"""
 
752
        
 
753
        args = self.split_arg(line)
 
754
        # Check argument's validity
 
755
        if '--no_default' in args:
 
756
            no_default = True
 
757
            args.remove('--no_default')
 
758
        else:
 
759
            no_default = False
 
760
 
 
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) 
 
767
 
 
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')):
 
770
            if no_default:
 
771
                logger.info('No pgs_card detected, so not run pgs')
 
772
                return 
 
773
            
 
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.')        
 
777
        
 
778
        if not (no_default or self.force):
 
779
            self.ask_edit_cards(['pgs_card.dat'])
 
780
            
 
781
        self.update_status('prepare PGS run', level=None)  
 
782
 
 
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']
 
787
        
 
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)
 
792
        
 
793
        self.update_status('Running PGS', level='pgs')
 
794
        
 
795
        tag = self.run_tag
 
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)
 
801
        else:
 
802
            open(banner_path, 'w').close()
 
803
 
 
804
        ########################################################################
 
805
        # now pass the event to a detector simulator and reconstruct objects
 
806
        ########################################################################
 
807
        if lock:
 
808
            lock.acquire()
 
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']
 
817
            ff.writelines(text)
 
818
        ff.close()
 
819
 
 
820
        try: 
 
821
            os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
 
822
        except Exception:
 
823
            pass
 
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)
 
828
        
 
829
        if not os.path.exists(pjoin(self.me_dir, 'Events', 'pgs.done')):
 
830
            logger.error('Fail to create LHCO events')
 
831
            return 
 
832
        else:
 
833
            os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
 
834
            
 
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 '))
 
839
 
 
840
        # Creating Root file
 
841
        if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHCOlympicsConverter')):
 
842
            self.update_status('Creating PGS Root File', level='pgs')
 
843
            try:
 
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')) 
 
847
            except Exception:
 
848
                logger.warning('fail to produce Root output [problem with ExRootAnalysis')
 
849
        if os.path.exists(pjoin(self.me_dir, 'Events', 'pgs_events.lhco')):
 
850
            # Creating plots
 
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)])
 
856
 
 
857
        self.update_status('finish', level='pgs', makehtml=False)
 
858
 
 
859
    ############################################################################
 
860
    def do_delphes(self, line):
 
861
        """ run delphes and make associate root file/plot """
 
862
 
 
863
        args = self.split_arg(line)
 
864
        # Check argument's validity
 
865
        if '--no_default' in args:
 
866
            no_default = True
 
867
            args.remove('--no_default')
 
868
        else:
 
869
            no_default = False
 
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)
 
877
        
 
878
        
 
879
        if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
 
880
            delphes3 = False
 
881
            prog = '../bin/internal/run_delphes'
 
882
        else:
 
883
            delphes3 = True
 
884
            prog =  '../bin/internal/run_delphes3'
 
885
                
 
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')):
 
889
            if no_default:
 
890
                logger.info('No delphes_card detected, so not run Delphes')
 
891
                return
 
892
            
 
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):
 
900
            if delphes3:
 
901
                self.ask_edit_cards(['delphes_card.dat'], args)
 
902
            else:
 
903
                self.ask_edit_cards(['delphes_card.dat', 'delphes_trigger.dat'], args)
 
904
            
 
905
        self.update_status('Running Delphes', level=None)  
 
906
        # Wait that the gunzip of the files is finished (if any)
 
907
        if lock:
 
908
            lock.acquire()
 
909
 
 
910
 
 
911
 
 
912
        delphes_dir = self.options['delphes_path']
 
913
        tag = self.run_tag
 
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'))
 
916
            if not delphes3:
 
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)))
 
919
        
 
920
        cross = self.results[self.run_name].get_current_info()['cross']
 
921
                    
 
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'))
 
927
                
 
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')
 
931
            return 
 
932
        
 
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)
 
937
            
 
938
        #eradir = self.options['exrootanalysis_path']
 
939
        madir = self.options['madanalysis_path']
 
940
        td = self.options['td_path']
 
941
 
 
942
        # Creating plots
 
943
        self.create_plot('Delphes')
 
944
 
 
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)])
 
947
 
 
948
 
 
949
        
 
950
        self.update_status('delphes done', level='delphes', makehtml=False)   
 
951
 
 
952
    ############################################################################ 
 
953
    def get_pid_final_states(self):
 
954
        """Find the pid of all particles in the final states"""
 
955
        pids = set()
 
956
        subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 
 
957
                                                                 'subproc.mg'))]
 
958
        nb_init = self.ninitial
 
959
        pat = re.compile(r'''DATA \(IDUP\(I,\d+\),I=1,\d+\)/([\+\-\d,\s]*)/''', re.I)
 
960
        for Pdir in subproc:
 
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:]))
 
966
        
 
967
        return pids
 
968
                
 
969
    ############################################################################
 
970
    def get_pdf_input_filename(self):
 
971
        """return the name of the file which is used by the pdfset"""
 
972
        
 
973
        if hasattr(self, 'pdffile') and self.pdffile:
 
974
            return self.pdffile
 
975
        else:
 
976
            for line in open(pjoin(self.me_dir,'Source','PDF','pdf_list.txt')):
 
977
                data = line.split()
 
978
                if len(data) < 4:
 
979
                    continue
 
980
                if data[1].lower() == self.run_card['pdlabel'].lower():
 
981
                    self.pdffile = pjoin(self.me_dir, 'lib', 'Pdfdata', data[2])
 
982
                    return self.pdffile 
 
983
            else:
 
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')
 
988
                return self.pdffile
 
989
                
 
990
                
 
991
        
 
992
  
 
993
    ############################################################################ 
 
994
    def do_open(self, line):
 
995
        """Open a text file/ eps file / html file"""
 
996
        
 
997
        args = self.split_arg(line)
 
998
        # Check Argument validity and modify argument to be the real path
 
999
        self.check_open(args)
 
1000
        file_path = args[0]
 
1001
        
 
1002
        misc.open_file(file_path)
 
1003
 
 
1004
    ############################################################################
 
1005
    def do_set(self, line, log=True):
 
1006
        """Set an option, which will be default for coming generations/outputs
 
1007
        """
 
1008
        # cmd calls automaticaly post_set after this command.
 
1009
 
 
1010
 
 
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')
 
1017
        
 
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]))
 
1022
            else:
 
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':
 
1028
                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':
 
1040
                args[1] = None
 
1041
            self.options[args[0]] = args[1]
 
1042
            opt = self.options
 
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
 
1050
                return
 
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':
 
1058
            if '(' in args[1]:
 
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]
 
1062
            else: 
 
1063
                first, second = args[1:3]            
 
1064
            
 
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])
 
1074
                else:
 
1075
                    raise self.InvalidCmd('Not a valid path: keep previous value: \'%s\'' % self.options[args[0]])
 
1076
            else:
 
1077
                self.options[args[0]] = args[1]             
 
1078
 
 
1079
    def configure_run_mode(self, run_mode):
 
1080
        """change the way to submit job 0: single core, 1: cluster, 2: multicore"""
 
1081
        
 
1082
        self.cluster_mode = run_mode
 
1083
        
 
1084
        if run_mode == 2:
 
1085
            if not self.nb_core:
 
1086
                import multiprocessing
 
1087
                self.nb_core = multiprocessing.cpu_count()
 
1088
            nb_core =self.nb_core
 
1089
        elif run_mode == 0:
 
1090
            nb_core = 1 
 
1091
            
 
1092
        if run_mode in [0, 2]:
 
1093
            self.cluster = cluster.MultiCore(nb_core, 
 
1094
                             cluster_temp_path=self.options['cluster_temp_path'])
 
1095
            
 
1096
        if self.cluster_mode == 1:
 
1097
            opt = self.options
 
1098
            cluster_name = opt['cluster_type']
 
1099
            self.cluster = cluster.from_name[cluster_name](**opt)
 
1100
 
 
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"""
 
1103
 
 
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))
 
1112
            if errortype:
 
1113
                self.results.current.debug = errortype
 
1114
            else:
 
1115
                self.results.current.debug = self.debug_output
 
1116
            
 
1117
        else:
 
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)
 
1124
 
 
1125
 
 
1126
  
 
1127
 
 
1128
    def update_status(self, status, level, makehtml=True, force=True, 
 
1129
                      error=False, starttime = None, update_results=True):
 
1130
        """ update the index status """
 
1131
        
 
1132
        if makehtml and not force:
 
1133
            if hasattr(self, 'next_update') and time.time() < self.next_update:
 
1134
                return
 
1135
            else:
 
1136
                self.next_update = time.time() + 3
 
1137
        
 
1138
        if isinstance(status, str):
 
1139
            if '<br>' not  in status:
 
1140
                logger.info(status)
 
1141
        elif starttime:
 
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))
 
1145
        else: 
 
1146
            logger.info(' Idle: %s,  Running: %s,  Completed: %s' % status[:3])
 
1147
        
 
1148
        if update_results:
 
1149
            self.results.update(status, level, makehtml=makehtml, error=error)
 
1150
        
 
1151
        
 
1152
    ############################################################################
 
1153
    def keep_cards(self, need_card=[]):
 
1154
        """Ask the question when launching generate_events/multi_run"""
 
1155
        
 
1156
        check_card = ['pythia_card.dat', 'pgs_card.dat','delphes_card.dat',
 
1157
                      'delphes_trigger.dat', 'madspin_card.dat', 'shower_card.dat']
 
1158
        
 
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))
 
1164
            else:
 
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)) 
 
1168
                
 
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 """
 
1173
            
 
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) 
 
1178
            
 
1179
        if not config_path:
 
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)
 
1183
                return
 
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)
 
1189
            if amcatnlo:
 
1190
                me5_config = pjoin(self.me_dir, 'Cards', 'amcatnlo_configuration.txt')
 
1191
            else:
 
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)
 
1194
                
 
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)
 
1200
 
 
1201
        config_file = open(config_path)
 
1202
 
 
1203
        # read the file and extract information
 
1204
        logger.info('load configuration from %s ' % config_file.name)
 
1205
        for line in config_file:
 
1206
            if '#' in line:
 
1207
                line = line.split('#',1)[0]
 
1208
            line = line.replace('\n','').replace('\r\n','')
 
1209
            try:
 
1210
                name, value = line.split('=')
 
1211
            except ValueError:
 
1212
                pass
 
1213
            else:
 
1214
                name = name.strip()
 
1215
                value = value.strip()
 
1216
                if name.endswith('_path'):
 
1217
                    path = value
 
1218
                    if os.path.isdir(path):
 
1219
                        self.options[name] = os.path.realpath(path)
 
1220
                        continue
 
1221
                    if not initdir:
 
1222
                        continue
 
1223
                    path = pjoin(initdir, value)
 
1224
                    if os.path.isdir(path):
 
1225
                        self.options[name] = os.path.realpath(path)
 
1226
                        continue
 
1227
                else:
 
1228
                    self.options[name] = value
 
1229
                    if value.lower() == "none":
 
1230
                        self.options[name] = None
 
1231
 
 
1232
        if not final:
 
1233
            return self.options # the return is usefull for unittest
 
1234
 
 
1235
 
 
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]
 
1242
                if path is None:
 
1243
                    continue
 
1244
                if os.path.isdir(path):
 
1245
                    self.options[key] = os.path.realpath(path)
 
1246
                    continue
 
1247
                path = pjoin(self.me_dir, self.options[key])
 
1248
                if os.path.isdir(path):
 
1249
                    self.options[key] = os.path.realpath(path)
 
1250
                    continue
 
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)
 
1255
                        continue
 
1256
                self.options[key] = None
 
1257
            elif key.startswith('cluster'):
 
1258
                pass              
 
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
 
1264
                try:
 
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" \
 
1268
                                   % key)
 
1269
        
 
1270
        # Configure the way to open a file:
 
1271
        misc.open_file.configure(self.options)
 
1272
          
 
1273
        return self.options
 
1274
 
 
1275
    @staticmethod
 
1276
    def find_available_run_name(me_dir):
 
1277
        """ find a valid run_name for the current job """
 
1278
        
 
1279
        name = 'run_%02d'
 
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) 
 
1283
    
 
1284
 
 
1285
    ############################################################################      
 
1286
    def do_decay_events(self,line):
 
1287
        """Require MG5 directory: decay events with spin correlations
 
1288
        """
 
1289
 
 
1290
        if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')):
 
1291
            return
 
1292
                
 
1293
        # First need to load MadSpin
 
1294
        
 
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'''
 
1299
        elif MADEVENT:
 
1300
            sys.path.append(self.options['mg5_path'])
 
1301
        try:
 
1302
            import MadSpin.decay as decay
 
1303
            import MadSpin.interface_madspin as interface_madspin
 
1304
        except ImportError:
 
1305
            raise self.ConfigurationError, '''Can\'t load MadSpin
 
1306
            The variable mg5_path might not be correctly configured.'''
 
1307
        
 
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)
 
1313
 
 
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]) 
 
1319
        
 
1320
 
 
1321
        path = pjoin(self.me_dir, 'Cards', 'madspin_card.dat')
 
1322
        madspin_cmd.import_command_file(path)
 
1323
                
 
1324
        # create a new run_name directory for this output
 
1325
        i = 1
 
1326
        while os.path.exists(pjoin(self.me_dir,'Events', '%s_decayed_%i' % (self.run_name,i))):
 
1327
            i+=1
 
1328
        new_run = '%s_decayed_%i' % (self.run_name,i)
 
1329
        evt_dir = pjoin(self.me_dir, 'Events')
 
1330
        
 
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'
 
1337
                new_file += '.gz'
 
1338
            else:
 
1339
                logger.error('MadSpin fails to create any decayed file.')
 
1340
                return
 
1341
        
 
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)        
 
1345
 
 
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')
 
1358
    
 
1359
    def complete_decay_events(self, text, line, begidx, endidx):
 
1360
        args = self.split_arg(line[0:begidx], error=False)
 
1361
        if len(args) == 1:
 
1362
            return self.complete_plot(text, line, begidx, endidx)
 
1363
        else:
 
1364
            return
 
1365
        
 
1366
 
 
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"""
 
1370
    
 
1371
    def __init__(self, question, cards=[], mode='auto', *args, **opt):
 
1372
        
 
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'))
 
1376
        try:
 
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'))   
 
1384
    
 
1385
        self.pname2block = {}
 
1386
        self.conflict = []
 
1387
        self.restricted_value = {}
 
1388
        self.mode = mode
 
1389
        self.cards = cards
 
1390
        
 
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
 
1393
        # model.
 
1394
        for bname, block in default_param.items():
 
1395
            for lha_id, param in block.param_dict.items():
 
1396
                all_var = []
 
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
 
1405
                else:
 
1406
                    split = comment.split()
 
1407
                    if len(split) >2 and split[1] == ':':
 
1408
                        # NO VAR associated
 
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()]
 
1413
                    else:
 
1414
                        # not recognized format
 
1415
                        continue
 
1416
                    
 
1417
                for var in all_var:
 
1418
                    var = var.lower()
 
1419
                    if var in self.pname2block:
 
1420
                        self.pname2block[var].append((bname, lha_id))
 
1421
                    else:
 
1422
                        self.pname2block[var] = [(bname, lha_id)]
 
1423
        
 
1424
                    
 
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)        
 
1429
                            
 
1430
    
 
1431
    def complete_set(self, text, line, begidx, endidx):
 
1432
        """ Complete the set command"""
 
1433
 
 
1434
        prev_timer = signal.alarm(0) # avoid timer if any
 
1435
        if prev_timer:
 
1436
            nb_back = len(line)
 
1437
            self.stdout.write('\b'*nb_back + '[timer stopped]\n')
 
1438
            self.stdout.write(line)
 
1439
            self.stdout.flush()
 
1440
        
 
1441
        possibilities = {}
 
1442
        allowed = {}
 
1443
        args = self.split_arg(line[0:begidx])
 
1444
        if len(args) == 1:
 
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'}
 
1455
            else:
 
1456
                allowed = {'value':''}
 
1457
        else:
 
1458
            start = 1
 
1459
            if args[1] in  ['run_card', 'param_card']:
 
1460
                start = 2
 
1461
            if args[start] in self.param_card.keys():
 
1462
                if args[start+1:]:
 
1463
                    allowed = {'block':(args[start], args[start+1:])}
 
1464
                else:
 
1465
                    allowed = {'block':args[start]}
 
1466
            elif len(args) == start +1:
 
1467
                    allowed['value'] = ''
 
1468
 
 
1469
            
 
1470
        if 'category' in allowed.keys():
 
1471
            possibilities['category of parameter (optional)'] = \
 
1472
                          self.list_completion(text, ['run_card', 'param_card'])
 
1473
        
 
1474
        if 'run_card' in allowed.keys():
 
1475
            opts = self.run_card.keys()
 
1476
            if allowed['run_card'] == 'default':
 
1477
                opts.append('default')
 
1478
            
 
1479
            possibilities['Run Card'] = self.list_completion(text, opts)
 
1480
 
 
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)
 
1486
                                
 
1487
        if 'value' in allowed.keys():
 
1488
            opts = ['default']
 
1489
            if 'decay' in args:
 
1490
                opts.append('Auto')
 
1491
            if args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay':
 
1492
                opts.append('Auto')
 
1493
            possibilities['Special Value'] = self.list_completion(text, opts)
 
1494
                 
 
1495
 
 
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,
 
1511
                                                                        varname)
 
1512
            else:
 
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]]
 
1517
                
 
1518
                if not ids:
 
1519
                    if tuple([int(i) for i in allowed['block'][1]]) in block:
 
1520
                        opts = ['default']
 
1521
                        if allowed['block'][0] == 'decay':
 
1522
                            opts.append('Auto')
 
1523
                        possibilities['Special value'] = self.list_completion(text, opts)
 
1524
                possibilities['Param Card id' ] = self.list_completion(text, ids)        
 
1525
 
 
1526
        return self.deal_multiple_categories(possibilities)
 
1527
           
 
1528
    def do_set(self, line):
 
1529
        """ edit the value of one parameter in the card"""
 
1530
 
 
1531
        args = self.split_arg(line.lower())
 
1532
        start = 0
 
1533
        if len(args) < 2:
 
1534
            logger.warning('invalid set command %s' % line)
 
1535
            return
 
1536
 
 
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]))
 
1543
                return
 
1544
            else:
 
1545
                card = args[0]
 
1546
            start=1
 
1547
            if len(args) < 3:
 
1548
                logger.warning('invalid set command: %s' % line)
 
1549
                return
 
1550
 
 
1551
        #### RUN CARD
 
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)
 
1556
                return
 
1557
                
 
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]]) 
 
1562
                else:
 
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.')
 
1568
            else:
 
1569
                try:
 
1570
                    val = eval(args[start+1])
 
1571
                except NameError:
 
1572
                    val = args[start+1]
 
1573
                self.setR(args[start], val)
 
1574
            self.run_card.write(pjoin(self.me_dir,'Cards','run_card.dat'))
 
1575
            
 
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'
 
1581
                
 
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)
 
1585
                return
 
1586
            
 
1587
            if args[start+1] in self.pname2block:
 
1588
                all_var = self.pname2block[args[start+1]]
 
1589
                key = None
 
1590
                for bname, lhaid in all_var:
 
1591
                    if bname == args[start]:
 
1592
                        key = lhaid
 
1593
                        break
 
1594
                else:
 
1595
                    logger.warning('%s is not part of block "%s" but "%s". please correct.' %
 
1596
                                    (args[start+1], args[start], bname))
 
1597
                    return
 
1598
            else:
 
1599
                try:
 
1600
                    key = tuple([int(i) for i in args[start+1:-1]])
 
1601
                except ValueError:
 
1602
                    logger.warning('invalid set command %s' % line)
 
1603
                    return 
 
1604
 
 
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)
 
1612
                
 
1613
                if args[-1].lower() in ['default', 'auto']:
 
1614
                    self.setP(args[start], key, args[-1])   
 
1615
                else:
 
1616
                    try:
 
1617
                        value = float(args[-1])
 
1618
                    except Exception:
 
1619
                        logger.warning('Invalid input: Expected number and not \'%s\'' \
 
1620
                                                                     % args[-1])
 
1621
                        return
 
1622
                    self.setP(args[start], key, value)
 
1623
            else:
 
1624
                logger.warning('invalid set command %s' % line)
 
1625
                return                   
 
1626
            self.param_card.write(pjoin(self.me_dir,'Cards','param_card.dat'))
 
1627
        
 
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')
 
1640
        #INVALID
 
1641
        else:
 
1642
            logger.warning('invalid set command %s' % line)
 
1643
            return            
 
1644
    
 
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
 
1648
        
 
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
 
1655
        
 
1656
            elif value == 'auto':
 
1657
                value = 'Auto'
 
1658
                if block != 'decay':
 
1659
                    logger.warning('Invalid input: \'Auto\' value only valid for DECAY')
 
1660
                    return
 
1661
            else:
 
1662
                try:
 
1663
                    value = float(value)
 
1664
                except ValueError:
 
1665
                    logger.warning('Invalid input: \'%s\' not valid intput.'% value)
 
1666
                    
 
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
 
1670
        
 
1671
      
 
1672
    def help_set(self):
 
1673
        '''help message for set'''
 
1674
        
 
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]")
 
1678
        logger.info('')
 
1679
        logger.info('-- Edit the param_card/run_card and replace the value of the')
 
1680
        logger.info('    parameter by the value VALUE.')
 
1681
        logger.info('   ')
 
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')
 
1687
        logger.info('')
 
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')
 
1695
        logger.info('')
 
1696
        logger.info('     set param_card default #return all parameter to default')
 
1697
        logger.info('     set run_card default')
 
1698
        logger.info('********************* HELP SET ***************************')
 
1699
 
 
1700
 
 
1701
    def default(self, line):
 
1702
        """Default action if line is not recognized"""
 
1703
 
 
1704
        line = line.strip()
 
1705
        args = line.split()
 
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'
 
1718
        else:
 
1719
            self.value = line
 
1720
        
 
1721
        return line
 
1722
    
 
1723
 
 
1724
        
 
1725
    def copy_file(self, path):
 
1726
        """detect the type of the file and overwritte the current file"""
 
1727
        
 
1728
        card_name = CommonRunCmd.detect_card_type(path)
 
1729
        
 
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)
 
1740
 
 
1741
    def open_file(self, answer):
 
1742
        """open the file"""
 
1743
        me_dir = self.mother_interface.me_dir
 
1744
        if answer.isdigit():
 
1745
            if answer == '9':
 
1746
                answer = 'plot'
 
1747
            else:
 
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)
 
1752
            else:
 
1753
                path = pjoin(me_dir,'Cards','delphes_trigger.dat')
 
1754
        else:
 
1755
            path = pjoin(me_dir, 'Cards', answer)
 
1756
        self.mother_interface.exec_cmd('open %s' % path)
 
1757
 
 
1758