~maddevelopers/mg5amcnlo/WWW5_caching

« back to all changes in this revision

Viewing changes to users/mardelcourt/PROC_427003/PROC_427003/bin/internal/madevent_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 glob
 
23
import logging
 
24
import math
 
25
import optparse
 
26
import os
 
27
import pydoc
 
28
import random
 
29
import re
 
30
import signal
 
31
import shutil
 
32
import stat
 
33
import subprocess
 
34
import sys
 
35
import traceback
 
36
import time
 
37
 
 
38
try:
 
39
    import readline
 
40
    GNU_SPLITTING = ('GNU' in readline.__doc__)
 
41
except:
 
42
    GNU_SPLITTING = True
 
43
 
 
44
root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
 
45
root_path = os.path.split(root_path)[0]
 
46
sys.path.insert(0, os.path.join(root_path,'bin'))
 
47
 
 
48
# usefull shortcut
 
49
pjoin = os.path.join
 
50
# Special logger for the Cmd Interface
 
51
logger = logging.getLogger('madevent.stdout') # -> stdout
 
52
logger_stderr = logging.getLogger('madevent.stderr') # ->stderr
 
53
 
 
54
try:
 
55
    # import from madgraph directory
 
56
    import madgraph.interface.extended_cmd as cmd
 
57
    import madgraph.interface.common_run_interface as common_run
 
58
    import madgraph.iolibs.files as files
 
59
    import madgraph.iolibs.save_load_object as save_load_object
 
60
    import madgraph.various.banner as banner_mod
 
61
    import madgraph.various.cluster as cluster
 
62
    import madgraph.various.gen_crossxhtml as gen_crossxhtml
 
63
    import madgraph.various.sum_html as sum_html
 
64
    import madgraph.various.misc as misc
 
65
    import madgraph.various.combine_runs as combine_runs
 
66
 
 
67
    import models.check_param_card as check_param_card    
 
68
    from madgraph import InvalidCmd, MadGraph5Error, MG5DIR
 
69
    MADEVENT = False
 
70
except ImportError, error:
 
71
    if __debug__:
 
72
        print error
 
73
    # import from madevent directory
 
74
    import internal.extended_cmd as cmd
 
75
    import internal.common_run_interface as common_run
 
76
    import internal.banner as banner_mod
 
77
    import internal.misc as misc    
 
78
    from internal import InvalidCmd, MadGraph5Error
 
79
    import internal.files as files
 
80
    import internal.gen_crossxhtml as gen_crossxhtml
 
81
    import internal.save_load_object as save_load_object
 
82
    import internal.cluster as cluster
 
83
    import internal.check_param_card as check_param_card
 
84
    import internal.sum_html as sum_html
 
85
    import internal.combine_runs as combine_runs
 
86
    MADEVENT = True
 
87
 
 
88
class MadEventError(Exception):
 
89
    pass
 
90
 
 
91
class ZeroResult(MadEventError):
 
92
    pass
 
93
 
 
94
#===============================================================================
 
95
# CmdExtended
 
96
#===============================================================================
 
97
class CmdExtended(common_run.CommonRunCmd):
 
98
    """Particularisation of the cmd command for MadEvent"""
 
99
 
 
100
    #suggested list of command
 
101
    next_possibility = {
 
102
        'start': [],
 
103
    }
 
104
    
 
105
    debug_output = 'ME5_debug'
 
106
    error_debug = 'Please report this bug on https://bugs.launchpad.net/madgraph5\n'
 
107
    error_debug += 'More information is found in \'%(debug)s\'.\n' 
 
108
    error_debug += 'Please attach this file to your report.'
 
109
 
 
110
    config_debug = 'If you need help with this issue please contact us on https://answers.launchpad.net/madgraph5\n'
 
111
 
 
112
 
 
113
    keyboard_stop_msg = """stopping all operation
 
114
            in order to quit madevent please enter exit"""
 
115
    
 
116
    # Define the Error
 
117
    InvalidCmd = InvalidCmd
 
118
    ConfigurationError = MadGraph5Error
 
119
 
 
120
    def __init__(self, me_dir, options, *arg, **opt):
 
121
        """Init history and line continuation"""
 
122
        
 
123
        # Tag allowing/forbiding question
 
124
        self.force = False
 
125
        
 
126
        # If possible, build an info line with current version number 
 
127
        # and date, from the VERSION text file
 
128
        info = misc.get_pkg_info()
 
129
        info_line = ""
 
130
        if info and info.has_key('version') and  info.has_key('date'):
 
131
            len_version = len(info['version'])
 
132
            len_date = len(info['date'])
 
133
            if len_version + len_date < 30:
 
134
                info_line = "#*         VERSION %s %s %s         *\n" % \
 
135
                            (info['version'],
 
136
                            (30 - len_version - len_date) * ' ',
 
137
                            info['date'])
 
138
        else:
 
139
            version = open(pjoin(root_path,'MGMEVersion.txt')).readline().strip()
 
140
            info_line = "#*         VERSION %s %s                *\n" % \
 
141
                            (version, (24 - len(version)) * ' ')    
 
142
 
 
143
        # Create a header for the history file.
 
144
        # Remember to fill in time at writeout time!
 
145
        self.history_header = \
 
146
        '#************************************************************\n' + \
 
147
        '#*                    MadGraph/MadEvent 5                   *\n' + \
 
148
        '#*                                                          *\n' + \
 
149
        "#*                *                       *                 *\n" + \
 
150
        "#*                  *        * *        *                   *\n" + \
 
151
        "#*                    * * * * 5 * * * *                     *\n" + \
 
152
        "#*                  *        * *        *                   *\n" + \
 
153
        "#*                *                       *                 *\n" + \
 
154
        "#*                                                          *\n" + \
 
155
        "#*                                                          *\n" + \
 
156
        info_line + \
 
157
        "#*                                                          *\n" + \
 
158
        "#*    The MadGraph Development Team - Please visit us at    *\n" + \
 
159
        "#*    https://server06.fynu.ucl.ac.be/projects/madgraph     *\n" + \
 
160
        '#*                                                          *\n' + \
 
161
        '#************************************************************\n' + \
 
162
        '#*                                                          *\n' + \
 
163
        '#*               Command File for MadEvent                  *\n' + \
 
164
        '#*                                                          *\n' + \
 
165
        '#*     run as ./bin/madevent.py filename                    *\n' + \
 
166
        '#*                                                          *\n' + \
 
167
        '#************************************************************\n'
 
168
        
 
169
        if info_line:
 
170
            info_line = info_line[1:]
 
171
 
 
172
        logger.info(\
 
173
        "************************************************************\n" + \
 
174
        "*                                                          *\n" + \
 
175
        "*           W E L C O M E  to  M A D G R A P H  5          *\n" + \
 
176
        "*                      M A D E V E N T                     *\n" + \
 
177
        "*                                                          *\n" + \
 
178
        "*                 *                       *                *\n" + \
 
179
        "*                   *        * *        *                  *\n" + \
 
180
        "*                     * * * * 5 * * * *                    *\n" + \
 
181
        "*                   *        * *        *                  *\n" + \
 
182
        "*                 *                       *                *\n" + \
 
183
        "*                                                          *\n" + \
 
184
        info_line + \
 
185
        "*                                                          *\n" + \
 
186
        "*    The MadGraph Development Team - Please visit us at    *\n" + \
 
187
        "*    https://server06.fynu.ucl.ac.be/projects/madgraph     *\n" + \
 
188
        "*                                                          *\n" + \
 
189
        "*               Type 'help' for in-line help.              *\n" + \
 
190
        "*                                                          *\n" + \
 
191
        "************************************************************")
 
192
        super(CmdExtended, self).__init__(me_dir, options, *arg, **opt)
 
193
        
 
194
    def get_history_header(self):
 
195
        """return the history header""" 
 
196
        return self.history_header % misc.get_time_info()
 
197
    
 
198
    def stop_on_keyboard_stop(self):
 
199
        """action to perform to close nicely on a keyboard interupt"""
 
200
        try:
 
201
            if hasattr(self, 'cluster'):
 
202
                logger.info('rm jobs on queue')
 
203
                self.cluster.remove()
 
204
            if hasattr(self, 'results'):
 
205
                self.update_status('Stop by the user', level=None, makehtml=False, error=True)
 
206
                self.add_error_log_in_html(KeyboardInterrupt)
 
207
        except:
 
208
            pass
 
209
    
 
210
    def postcmd(self, stop, line):
 
211
        """ Update the status of  the run for finishing interactive command """
 
212
        
 
213
        stop = super(CmdExtended, self).postcmd(stop, line)   
 
214
        # relaxing the tag forbidding question
 
215
        self.force = False
 
216
        
 
217
        if not self.use_rawinput:
 
218
            return stop
 
219
        
 
220
        if self.results and not self.results.current:
 
221
            return stop
 
222
        
 
223
        arg = line.split()
 
224
        if  len(arg) == 0:
 
225
            return stop
 
226
        if isinstance(self.results.status, str) and self.results.status.startswith('Error'):
 
227
            return stop
 
228
        if isinstance(self.results.status, str) and self.results.status == 'Stop by the user':
 
229
            self.update_status('%s Stop by the user' % arg[0], level=None, error=True)
 
230
            return stop        
 
231
        elif not self.results.status:
 
232
            return stop
 
233
        elif str(arg[0]) in ['exit','quit','EOF']:
 
234
            return stop
 
235
        
 
236
        try:
 
237
            self.update_status('Command \'%s\' done.<br> Waiting for instruction.' % arg[0], 
 
238
                               level=None, error=True)
 
239
        except Exception:
 
240
            misc.sprint('update_status fails')
 
241
            pass
 
242
        
 
243
    
 
244
    def nice_user_error(self, error, line):
 
245
        """If a ME run is currently running add a link in the html output"""
 
246
 
 
247
        self.add_error_log_in_html()
 
248
        cmd.Cmd.nice_user_error(self, error, line)            
 
249
        
 
250
    def nice_config_error(self, error, line):
 
251
        """If a ME run is currently running add a link in the html output"""
 
252
 
 
253
        self.add_error_log_in_html()
 
254
        cmd.Cmd.nice_config_error(self, error, line)
 
255
        
 
256
        
 
257
        try:
 
258
            debug_file = open(self.debug_output, 'a')
 
259
            debug_file.write(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')))
 
260
            debug_file.close()
 
261
        except:
 
262
            pass 
 
263
            
 
264
 
 
265
    def nice_error_handling(self, error, line):
 
266
        """If a ME run is currently running add a link in the html output"""
 
267
 
 
268
        if isinstance(error, ZeroResult):
 
269
            self.add_error_log_in_html(error)
 
270
            logger.warning('Zero result detected: %s' % error)
 
271
            # create a banner if needed
 
272
            try:
 
273
                if not self.banner:
 
274
                    self.banner = banner_mod.Banner()
 
275
                if 'slha' not in self.banner:
 
276
                    self.banner.add(pjoin(self.me_dir,'Cards','param_card.dat'))
 
277
                if 'mgruncard' not in self.banner:
 
278
                    self.banner.add(pjoin(self.me_dir,'Cards','run_card.dat'))
 
279
                if 'mg5proccard' not in self.banner:
 
280
                    proc_card = pjoin(self.me_dir,'Cards','proc_card_mg5.dat')
 
281
                    if os.path.exists(proc_card):
 
282
                        self.banner.add(proc_card)
 
283
                
 
284
                out_dir = pjoin(self.me_dir, 'Events', self.run_name)
 
285
                if not os.path.isdir(out_dir):
 
286
                    os.mkdir(out_dir)
 
287
                output_path = pjoin(out_dir, '%s_%s_banner.txt' % \
 
288
                                                  (self.run_name, self.run_tag))
 
289
                self.banner.write(output_path)
 
290
            except Exception:
 
291
                if __debug__:
 
292
                    raise
 
293
                else:
 
294
                    pass
 
295
        else:
 
296
            self.add_error_log_in_html()            
 
297
            cmd.Cmd.nice_error_handling(self, error, line)
 
298
            try:
 
299
                debug_file = open(self.debug_output, 'a')
 
300
                debug_file.write(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')))
 
301
                debug_file.close()
 
302
            except:
 
303
                pass
 
304
        
 
305
        
 
306
#===============================================================================
 
307
# HelpToCmd
 
308
#===============================================================================
 
309
class HelpToCmd(object):
 
310
    """ The Series of help routine for the MadEventCmd"""
 
311
    
 
312
    def help_banner_run(self):
 
313
        logger.info("syntax: banner_run Path|RUN [--run_options]")
 
314
        logger.info("-- Reproduce a run following a given banner")
 
315
        logger.info("   One of the following argument is require:")
 
316
        logger.info("   Path should be the path of a valid banner.")
 
317
        logger.info("   RUN should be the name of a run of the current directory")
 
318
        self.run_options_help([('-f','answer all question by default'),
 
319
                               ('--name=X', 'Define the name associated with the new run')]) 
 
320
    
 
321
    def help_open(self):
 
322
        logger.info("syntax: open FILE  ")
 
323
        logger.info("-- open a file with the appropriate editor.")
 
324
        logger.info('   If FILE belongs to index.html, param_card.dat, run_card.dat')
 
325
        logger.info('   the path to the last created/used directory is used')
 
326
        logger.info('   The program used to open those files can be chosen in the')
 
327
        logger.info('   configuration file ./input/mg5_configuration.txt')   
 
328
        
 
329
        
 
330
    def run_options_help(self, data):
 
331
        if data:
 
332
            logger.info('-- local options:')
 
333
            for name, info in data:
 
334
                logger.info('      %s : %s' % (name, info))
 
335
        
 
336
        logger.info("-- session options:")
 
337
        logger.info("      Note that those options will be kept for the current session")      
 
338
        logger.info("      --cluster : Submit to the  cluster. Current cluster: %s" % self.options['cluster_type'])
 
339
        logger.info("      --multicore : Run in multi-core configuration")
 
340
        logger.info("      --nb_core=X : limit the number of core to use to X.")
 
341
        
 
342
 
 
343
    def help_generate_events(self):
 
344
        logger.info("syntax: generate_events [run_name] [options])")
 
345
        logger.info("-- Launch the full chain of script for the generation of events")
 
346
        logger.info("   Including possible plotting, shower and detector resolution.")
 
347
        logger.info("   Those steps are performed if the related program are installed")
 
348
        logger.info("   and if the related card are present in the Cards directory.")
 
349
        self.run_options_help([('-f', 'Use default for all questions.'),
 
350
                               ('--laststep=', 'argument might be parton/pythia/pgs/delphes and indicate the last level to be run.')])
 
351
 
 
352
    
 
353
    def help_add_time_of_flight(self):
 
354
        logger.info("syntax: add_time_of_flight [run_name|path_to_file] [--treshold=]")
 
355
        logger.info('-- Add in the lhe files the information')
 
356
        logger.info('   of how long it takes to a particle to decay.')
 
357
        logger.info('   threshold option allows to change the minimal value required to')
 
358
        logger.info('   a non zero value for the particle (default:1e-12s)')
 
359
 
 
360
    def help_calculate_decay_widths(self):
 
361
        
 
362
        if self.ninitial != 1:
 
363
            logger.warning("This command is only valid for processes of type A > B C.")
 
364
            logger.warning("This command can not be run in current context.")
 
365
            logger.warning("")
 
366
        
 
367
        logger.info("syntax: calculate_decay_widths [run_name] [options])")
 
368
        logger.info("-- Calculate decay widths and enter widths and BRs in param_card")
 
369
        logger.info("   for a series of processes of type A > B C ...")
 
370
        self.run_options_help([('-f', 'Use default for all questions.'),
 
371
                               ('--accuracy=', 'accuracy (for each partial decay width).'\
 
372
                                + ' Default is 0.01.')])
 
373
 
 
374
    def help_multi_run(self):
 
375
        logger.info("syntax: multi_run NB_RUN [run_name] [--run_options])")
 
376
        logger.info("-- Launch the full chain of script for the generation of events")
 
377
        logger.info("   NB_RUN times. This chains includes possible plotting, shower")
 
378
        logger.info(" and detector resolution.")
 
379
        self.run_options_help([('-f', 'Use default for all questions.'),
 
380
                               ('--laststep=', 'argument might be parton/pythia/pgs/delphes and indicate the last level to be run.')])
 
381
 
 
382
    def help_survey(self):
 
383
        logger.info("syntax: survey [run_name] [--run_options])")
 
384
        logger.info("-- evaluate the different channel associate to the process")
 
385
        self.run_options_help([("--" + key,value[-1]) for (key,value) in \
 
386
                               self._survey_options.items()])
 
387
     
 
388
    def help_launch(self):
 
389
        """exec generate_events for 2>N and calculate_width for 1>N"""
 
390
        logger.info("syntax: launch [run_name] [options])")
 
391
        logger.info("    --alias for either generate_events/calculate_decay_widths")
 
392
        logger.info("      depending of the number of particles in the initial state.")
 
393
        
 
394
        if self.ninitial == 1:
 
395
            logger.info("For this directory this is equivalent to calculate_decay_widths")
 
396
            self.help_calculate_decay_widths()
 
397
        else:
 
398
            logger.info("For this directory this is equivalent to $generate_events")
 
399
            self.help_generate_events()
 
400
                 
 
401
    def help_refine(self):
 
402
        logger.info("syntax: refine require_precision [max_channel] [--run_options]")
 
403
        logger.info("-- refine the LAST run to achieve a given precision.")
 
404
        logger.info("   require_precision: can be either the targeted number of events")
 
405
        logger.info('                      or the required relative error')
 
406
        logger.info('   max_channel:[5] maximal number of channel per job')
 
407
        self.run_options_help([])
 
408
        
 
409
    def help_combine_events(self):
 
410
        """ """
 
411
        logger.info("syntax: combine_events [run_name] [--tag=tag_name] [--run_options]")
 
412
        logger.info("-- Combine the last run in order to write the number of events")
 
413
        logger.info("   asked in the run_card.")
 
414
        self.run_options_help([])
 
415
        
 
416
    def help_compute_widths(self):
 
417
        logger.info("syntax: compute_widths Particle [Particles] [Param_card] [--output=PATH]")
 
418
        logger.info("-- Compute the widths (ONLY 1->2) for the particles specified.")
 
419
        logger.info("   By default, this takes the current param_card and overwrites it.")       
 
420
 
 
421
    def help_store_events(self):
 
422
        """ """
 
423
        logger.info("syntax: store_events [--run_options]")
 
424
        logger.info("-- Write physically the events in the files.")
 
425
        logger.info("   should be launch after \'combine_events\'")
 
426
        self.run_options_help([])
 
427
 
 
428
    def help_create_gridpack(self):
 
429
        """ """
 
430
        logger.info("syntax: create_gridpack [--run_options]")
 
431
        logger.info("-- create the gridpack. ")
 
432
        logger.info("   should be launch after \'store_events\'")
 
433
        self.run_options_help([])
 
434
 
 
435
    def help_import(self):
 
436
        """ """
 
437
        logger.info("syntax: import command PATH")
 
438
        logger.info("-- Execute the command present in the file")
 
439
        self.run_options_help([])
 
440
        
 
441
    def help_remove(self):
 
442
        logger.info("syntax: remove RUN [all|parton|pythia|pgs|delphes|banner] [-f] [--tag=]")
 
443
        logger.info("-- Remove all the files linked to previous run RUN")
 
444
        logger.info("   if RUN is 'all', then all run will be cleaned.")
 
445
        logger.info("   The optional argument precise which part should be cleaned.")
 
446
        logger.info("   By default we clean all the related files but the banners.")
 
447
        logger.info("   the optional '-f' allows to by-pass all security question")
 
448
        logger.info("   The banner can be remove only if all files are removed first.")
 
449
 
 
450
#===============================================================================
 
451
# CheckValidForCmd
 
452
#===============================================================================
 
453
class CheckValidForCmd(object):
 
454
    """ The Series of check routine for the MadEventCmd"""
 
455
 
 
456
    def check_banner_run(self, args):
 
457
        """check the validity of line"""
 
458
        
 
459
        if len(args) == 0:
 
460
            self.help_banner_run()
 
461
            raise self.InvalidCmd('banner_run reauires at least one argument.')
 
462
        
 
463
        tag = [a[6:] for a in args if a.startswith('--tag=')]
 
464
        
 
465
        
 
466
        if os.path.exists(args[0]):
 
467
            type ='banner'
 
468
            format = self.detect_card_type(args[0])
 
469
            if format != 'banner':
 
470
                raise self.InvalidCmd('The file is not a valid banner.')
 
471
        elif tag:
 
472
            args[0] = pjoin(self.me_dir,'Events', args[0], '%s_%s_banner.txt' % \
 
473
                                    (args[0], tag))                  
 
474
            if not os.path.exists(args[0]):
 
475
                raise self.InvalidCmd('No banner associates to this name and tag.')
 
476
        else:
 
477
            name = args[0]
 
478
            type = 'run'
 
479
            banners = glob.glob(pjoin(self.me_dir,'Events', args[0], '*_banner.txt'))
 
480
            if not banners:
 
481
                raise self.InvalidCmd('No banner associates to this name.')    
 
482
            elif len(banners) == 1:
 
483
                args[0] = banners[0]
 
484
            else:
 
485
                #list the tag and propose those to the user
 
486
                tags = [os.path.basename(p)[len(args[0])+1:-11] for p in banners]
 
487
                tag = self.ask('which tag do you want to use?', tags[0], tags)
 
488
                args[0] = pjoin(self.me_dir,'Events', args[0], '%s_%s_banner.txt' % \
 
489
                                    (args[0], tag))                
 
490
                        
 
491
        run_name = [arg[7:] for arg in args if arg.startswith('--name=')]
 
492
        if run_name:
 
493
            try:
 
494
                self.exec_cmd('remove %s all banner -f' % run_name)
 
495
            except Exception:
 
496
                pass
 
497
            self.set_run_name(args[0], tag=None, level='parton', reload_card=True)
 
498
        elif type == 'banner':
 
499
            self.set_run_name(self.find_available_run_name(self.me_dir))
 
500
        elif type == 'run':
 
501
            if not self.results[name].is_empty():
 
502
                run_name = self.find_available_run_name(self.me_dir)
 
503
                logger.info('Run %s is not empty so will use run_name: %s' % \
 
504
                                                               (name, run_name))
 
505
                self.set_run_name(run_name)
 
506
            else:
 
507
                try:
 
508
                    self.exec_cmd('remove %s all banner -f' % run_name)
 
509
                except Exception:
 
510
                    pass
 
511
                self.set_run_name(name)
 
512
            
 
513
    def check_history(self, args):
 
514
        """check the validity of line"""
 
515
        
 
516
        if len(args) > 1:
 
517
            self.help_history()
 
518
            raise self.InvalidCmd('\"history\" command takes at most one argument')
 
519
        
 
520
        if not len(args):
 
521
            return
 
522
        elif args[0] != 'clean':
 
523
                dirpath = os.path.dirname(args[0])
 
524
                if dirpath and not os.path.exists(dirpath) or \
 
525
                       os.path.isdir(args[0]):
 
526
                    raise self.InvalidCmd("invalid path %s " % dirpath)
 
527
                
 
528
    def check_save(self, args):
 
529
        """ check the validity of the line"""
 
530
        
 
531
        if len(args) == 0:
 
532
            args.append('options')
 
533
        
 
534
        if args[0] not in self._save_opts:
 
535
            raise self.InvalidCmd('wrong \"save\" format')
 
536
        
 
537
        if args[0] != 'options' and len(args) != 2:
 
538
            self.help_save()
 
539
            raise self.InvalidCmd('wrong \"save\" format')
 
540
        elif args[0] != 'options' and len(args) == 2:
 
541
            basename = os.path.dirname(args[1])
 
542
            if not os.path.exists(basename):
 
543
                raise self.InvalidCmd('%s is not a valid path, please retry' % \
 
544
                                                                        args[1])
 
545
        
 
546
        if args[0] == 'options':
 
547
            has_path = None
 
548
            for arg in args[1:]:
 
549
                if arg in ['--auto', '--all']:
 
550
                    continue
 
551
                elif arg.startswith('--'):
 
552
                    raise self.InvalidCmd('unknow command for \'save options\'')
 
553
                else:
 
554
                    basename = os.path.dirname(arg)
 
555
                    if not os.path.exists(basename):
 
556
                        raise self.InvalidCmd('%s is not a valid path, please retry' % \
 
557
                                                                        arg)
 
558
                    elif has_path:
 
559
                        raise self.InvalidCmd('only one path is allowed')
 
560
                    else:
 
561
                        args.remove(arg)
 
562
                        args.insert(1, arg)
 
563
                        has_path = True
 
564
            if not has_path:
 
565
                if '--auto' in arg and self.options['mg5_path']:
 
566
                    args.insert(1, pjoin(self.options['mg5_path'],'input','mg5_configuration.txt'))  
 
567
                else:
 
568
                    args.insert(1, pjoin(self.me_dir,'Cards','me5_configuration.txt'))  
 
569
    
 
570
    
 
571
    def check_survey(self, args, cmd='survey'):
 
572
        """check that the argument for survey are valid"""
 
573
        
 
574
        
 
575
        self.opts = dict([(key,value[1]) for (key,value) in \
 
576
                          self._survey_options.items()])
 
577
 
 
578
        # Treat any arguments starting with '--'
 
579
        while args and args[-1].startswith('--'):
 
580
            arg = args.pop(-1)
 
581
            try:
 
582
                for opt,value in self._survey_options.items():
 
583
                    if arg.startswith('--%s=' % opt):
 
584
                        exec('self.opts[\'%s\'] = %s(arg.split(\'=\')[-1])' % \
 
585
                             (opt, value[0]))
 
586
                        arg = ""
 
587
                if arg != "": raise Exception
 
588
            except Exception:
 
589
                self.help_survey()
 
590
                raise self.InvalidCmd('invalid %s argument'% arg)
 
591
 
 
592
        if len(args) > 1:
 
593
            self.help_survey()
 
594
            raise self.InvalidCmd('Too many argument for %s command' % cmd)
 
595
        elif not args:
 
596
            # No run name assigned -> assigned one automaticaly 
 
597
            self.set_run_name(self.find_available_run_name(self.me_dir))
 
598
        else:
 
599
            self.set_run_name(args[0], None,'parton', True)
 
600
            args.pop(0)
 
601
            
 
602
        return True
 
603
 
 
604
    def check_generate_events(self, args):
 
605
        """check that the argument for generate_events are valid"""
 
606
        
 
607
        run = None
 
608
        if args and args[-1].startswith('--laststep='):
 
609
            run = args[-1].split('=')[-1]
 
610
            if run not in ['auto','parton', 'pythia', 'pgs', 'delphes']:
 
611
                self.help_generate_events()
 
612
                raise self.InvalidCmd('invalid %s argument'% args[-1])
 
613
            if run != 'parton' and not self.options['pythia-pgs_path']:                
 
614
                raise self.InvalidCmd('''pythia-pgs not install. Please install this package first. 
 
615
                To do so type: \'install pythia-pgs\' in the mg5 interface''')
 
616
            if run == 'delphes' and not self.options['delphes_path']:
 
617
                raise self.InvalidCmd('''delphes not install. Please install this package first. 
 
618
                To do so type: \'install Delphes\' in the mg5 interface''')
 
619
            del args[-1]
 
620
                                
 
621
        if len(args) > 1:
 
622
            self.help_generate_events()
 
623
            raise self.InvalidCmd('Too many argument for generate_events command: %s' % cmd)
 
624
                    
 
625
        return run
 
626
 
 
627
    def check_add_time_of_flight(self, args):
 
628
        """check that the argument are correct"""
 
629
        
 
630
        
 
631
        if len(args) >2:
 
632
            self.help_time_of_flight()
 
633
            raise self.InvalidCmd('Too many arguments')
 
634
        
 
635
        # check if the threshold is define. and keep it's value
 
636
        if args and args[-1].startswith('--threshold='):
 
637
            try:
 
638
                threshold = float(args[-1].split('=')[1])
 
639
            except ValueError:
 
640
                raise self.InvalidCmd('threshold options require a number.')
 
641
            args.remove(args[-1])
 
642
        else:
 
643
            threshold = 1e-12
 
644
            
 
645
        if len(args) == 1 and  os.path.exists(args[0]): 
 
646
                event_path = args[0]
 
647
        else:
 
648
            if len(args) and self.run_name != args[0]:
 
649
                self.set_run_name(args.pop(0))
 
650
            elif not self.run_name:            
 
651
                self.help_add_time_of_flight()
 
652
                raise self.InvalidCmd('Need a run_name to process')            
 
653
            event_path = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')
 
654
            if not os.path.exists(event_path):
 
655
                event_path = event_path[:-3]
 
656
                if not os.path.exists(event_path):    
 
657
                    raise self.InvalidCmd('No unweighted events associate to this run.')
 
658
 
 
659
 
 
660
        
 
661
        #reformat the data
 
662
        args[:] = [event_path, threshold]
 
663
 
 
664
    def check_calculate_decay_widths(self, args):
 
665
        """check that the argument for calculate_decay_widths are valid"""
 
666
        
 
667
        if self.ninitial != 1:
 
668
            raise self.InvalidCmd('Can only calculate decay widths for decay processes A > B C ...')
 
669
 
 
670
        accuracy = 0.01
 
671
        run = None
 
672
        if args and args[-1].startswith('--accuracy='):
 
673
            try:
 
674
                accuracy = float(args[-1].split('=')[-1])
 
675
            except Exception:
 
676
                raise self.InvalidCmd('Argument error in calculate_decay_widths command')
 
677
            del args[-1]
 
678
        if len(args) > 1:
 
679
            self.help_calculate_decay_widths()
 
680
            raise self.InvalidCmd('Too many argument for calculate_decay_widths command: %s' % cmd)
 
681
                    
 
682
        return accuracy
 
683
 
 
684
 
 
685
 
 
686
    def check_multi_run(self, args):
 
687
        """check that the argument for survey are valid"""
 
688
 
 
689
        run = None
 
690
        
 
691
        if not len(args):
 
692
            self.help_multi_run()
 
693
            raise self.InvalidCmd("""multi_run command requires at least one argument for
 
694
            the number of times that it call generate_events command""")
 
695
            
 
696
        if args[-1].startswith('--laststep='):
 
697
            run = args[-1].split('=')[-1]
 
698
            if run not in ['parton', 'pythia', 'pgs', 'delphes']:
 
699
                self.help_multi_run()
 
700
                raise self.InvalidCmd('invalid %s argument'% args[-1])
 
701
            if run != 'parton' and not self.options['pythia-pgs_path']:                
 
702
                raise self.InvalidCmd('''pythia-pgs not install. Please install this package first. 
 
703
                To do so type: \'install pythia-pgs\' in the mg5 interface''')
 
704
            if run == 'delphes' and not self.options['delphes_path']:
 
705
                raise self.InvalidCmd('''delphes not install. Please install this package first. 
 
706
                To do so type: \'install Delphes\' in the mg5 interface''')
 
707
            del args[-1]
 
708
            
 
709
 
 
710
        elif not args[0].isdigit():
 
711
            self.help_multi_run()
 
712
            raise self.InvalidCmd("The first argument of multi_run should be a integer.")
 
713
        nb_run = args.pop(0)
 
714
        self.check_survey(args, cmd='multi_run')
 
715
        args.insert(0, int(nb_run))
 
716
        
 
717
        return run
 
718
 
 
719
    def check_refine(self, args):
 
720
        """check that the argument for survey are valid"""
 
721
 
 
722
        # if last argument is not a number -> it's the run_name (Not allow anymore)
 
723
        try:
 
724
            float(args[-1])
 
725
        except ValueError:
 
726
            self.help_refine()
 
727
            raise self.InvalidCmd('Not valid arguments')
 
728
        except IndexError:
 
729
            self.help_refine()
 
730
            raise self.InvalidCmd('require_precision argument is require for refine cmd')
 
731
 
 
732
    
 
733
        if not self.run_name:
 
734
            if self.results.lastrun:
 
735
                self.set_run_name(self.results.lastrun)
 
736
            else:
 
737
                raise self.InvalidCmd('No run_name currently define. Unable to run refine')
 
738
 
 
739
        if len(args) > 2:
 
740
            self.help_refine()
 
741
            raise self.InvalidCmd('Too many argument for refine command')
 
742
        else:
 
743
            try:
 
744
                [float(arg) for arg in args]
 
745
            except ValueError:         
 
746
                self.help_refine()    
 
747
                raise self.InvalidCmd('refine arguments are suppose to be number')
 
748
            
 
749
        return True
 
750
    
 
751
    def check_compute_widths(self, args):
 
752
        """check that the model is loadable and check that the format is of the
 
753
        type: PART PATH --output=PATH -f
 
754
        return the model.
 
755
        """
 
756
        
 
757
        # Check that MG5 directory is present .
 
758
        if MADEVENT and not self.options['mg5_path']:
 
759
            raise self.InvalidCmd, '''The automatic computations of widths requires that MG5 is installed on the system.
 
760
            You can install it and set his path in ./Cards/me5_configuration.txt'''
 
761
        elif MADEVENT:
 
762
            sys.path.append(self.options['mg5_path'])
 
763
        try:
 
764
            import models.model_reader as model_reader
 
765
            import models.import_ufo as import_ufo
 
766
        except ImportError:
 
767
            raise self.ConfigurationError, '''Can\'t load MG5.
 
768
            The variable mg5_path should not be correctly configure.'''
 
769
        
 
770
        ufo_path = pjoin(self.me_dir,'bin','internal', 'ufomodel')
 
771
        # Import model
 
772
        if not MADEVENT:
 
773
            modelname = self.find_model_name()
 
774
            restrict_file = None
 
775
            if os.path.exists(pjoin(ufo_path, 'restrict_default.dat')):
 
776
                restrict_file = pjoin(ufo_path, 'restrict_default.dat')
 
777
            model = import_ufo.import_model(modelname, decay=True, 
 
778
                        restrict_file=restrict_file)
 
779
            if self.mother.options['complex_mass_scheme']:
 
780
                model.change_mass_to_complex_scheme()
 
781
            
 
782
            
 
783
        else:
 
784
            model = import_ufo.import_model(pjoin(self.me_dir,'bin','internal', 'ufomodel'),
 
785
                                        decay=True)
 
786
            #pattern for checking complex mass scheme.
 
787
            has_cms = re.compile(r'''set\s+complex_mass_scheme\s*(True|T|1|true|$|;)''')
 
788
            if has_cms.search(open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')\
 
789
                                   ).read()):
 
790
                model.change_mass_to_complex_scheme()
 
791
   
 
792
        
 
793
            
 
794
        if not hasattr(model.get('particles')[0], 'partial_widths'):
 
795
            raise self.InvalidCmd, 'The UFO model does not include partial widths information. Impossible to compute widths automatically'
 
796
            
 
797
        # check if the name are passed to default MG5
 
798
        if '-modelname' in open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')).read():
 
799
            model.pass_particles_name_in_mg_default()        
 
800
        model = model_reader.ModelReader(model)
 
801
        particles_name = dict([(p.get('name'), p.get('pdg_code'))
 
802
                                               for p in model.get('particles')])
 
803
        
 
804
        output = {'model': model, 'model':model, 'force': False, 'output': None, 
 
805
                  'input':None, 'particles': set()}
 
806
        for arg in args:
 
807
            if arg.startswith('--output='):
 
808
                output_path = arg.split('=',1)[1]
 
809
                if not os.path.exists(output_path):
 
810
                    raise self.InvalidCmd, 'Invalid Path for the output. Please retry.'
 
811
                if not os.path.isfile(output_path):
 
812
                    output_path = pjoin(output_path, 'param_card.dat')
 
813
                output['output'] = output_path
 
814
            elif arg == '-f':
 
815
                output['force'] = True
 
816
            elif os.path.isfile(arg):
 
817
                type = self.detect_card_type(arg)
 
818
                if type != 'param_card.dat':
 
819
                    raise self.InvalidCmd , '%s is not a valid param_card.' % arg
 
820
                output['input'] = arg
 
821
            elif arg in particles_name:
 
822
                # should be a particles
 
823
                output['particles'].add(particles_name[arg])
 
824
            elif arg.isdigit() and int(arg) in particles_name.values():
 
825
                output['particles'].add(eval(arg))
 
826
            else:
 
827
                self.help_compute_widths()
 
828
                raise self.InvalidCmd, '%s is not a valid argument for compute_widths' % arg
 
829
 
 
830
        if not output['particles']:
 
831
            raise self.InvalidCmd, '''This routines requires at least one particle in order to compute
 
832
            the related width'''
 
833
            
 
834
        if output['output'] is None:
 
835
            output['output'] = output['input']
 
836
 
 
837
        return output
 
838
    
 
839
    def check_combine_events(self, arg):
 
840
        """ Check the argument for the combine events command """
 
841
        
 
842
        tag = [a for a in arg if a.startswith('--tag=')]
 
843
        if tag: 
 
844
            arg.remove(tag[0])
 
845
            tag = tag[0][6:]
 
846
        elif not self.run_tag:
 
847
            tag = 'tag_1'
 
848
        else:
 
849
            tag = self.run_tag
 
850
        self.run_tag = tag
 
851
     
 
852
        if len(arg) > 1:
 
853
            self.help_combine_events()
 
854
            raise self.InvalidCmd('Too many argument for combine_events command')
 
855
        
 
856
        if len(arg) == 1:
 
857
            self.set_run_name(arg[0], self.run_tag, 'parton', True)
 
858
        
 
859
        if not self.run_name:
 
860
            if not self.results.lastrun:
 
861
                raise self.InvalidCmd('No run_name currently define. Unable to run combine')
 
862
            else:
 
863
                self.set_run_name(self.results.lastrun)
 
864
        
 
865
        return True
 
866
    
 
867
    def check_pythia(self, args):
 
868
        """Check the argument for pythia command
 
869
        syntax: pythia [NAME] 
 
870
        Note that other option are already remove at this point
 
871
        """
 
872
        
 
873
        mode = None
 
874
        laststep = [arg for arg in args if arg.startswith('--laststep=')]
 
875
        if laststep and len(laststep)==1:
 
876
            mode = laststep[0].split('=')[-1]
 
877
            if mode not in ['auto', 'pythia', 'pgs', 'delphes']:
 
878
                self.help_pythia()
 
879
                raise self.InvalidCmd('invalid %s argument'% args[-1])     
 
880
        elif laststep:
 
881
            raise self.InvalidCmd('only one laststep argument is allowed')
 
882
     
 
883
        # If not pythia-pgs path
 
884
        if not self.options['pythia-pgs_path']:
 
885
            logger.info('Retry to read configuration file to find pythia-pgs path')
 
886
            self.set_configuration()
 
887
            
 
888
        if not self.options['pythia-pgs_path'] or not \
 
889
            os.path.exists(pjoin(self.options['pythia-pgs_path'],'src')):
 
890
            error_msg = 'No pythia-pgs path correctly set.'
 
891
            error_msg += 'Please use the set command to define the path and retry.'
 
892
            error_msg += 'You can also define it in the configuration file.'
 
893
            raise self.InvalidCmd(error_msg)
 
894
     
 
895
     
 
896
     
 
897
        tag = [a for a in args if a.startswith('--tag=')]
 
898
        if tag: 
 
899
            args.remove(tag[0])
 
900
            tag = tag[0][6:]
 
901
        
 
902
        if len(args) == 0 and not self.run_name:
 
903
            if self.results.lastrun:
 
904
                args.insert(0, self.results.lastrun)
 
905
            else:
 
906
                raise self.InvalidCmd('No run name currently define. Please add this information.')             
 
907
        
 
908
        if len(args) >= 1:
 
909
            if args[0] != self.run_name and\
 
910
             not os.path.exists(pjoin(self.me_dir,'Events',args[0], 'unweighted_events.lhe.gz')):
 
911
                raise self.InvalidCmd('No events file corresponding to %s run. '% args[0])
 
912
            self.set_run_name(args[0], tag, 'pythia')
 
913
        else:
 
914
            if tag:
 
915
                self.run_card['run_tag'] = tag
 
916
            self.set_run_name(self.run_name, tag, 'pythia')
 
917
 
 
918
        if  not os.path.exists(pjoin(self.me_dir,'Events',self.run_name,'unweighted_events.lhe.gz')):
 
919
            raise self.InvalidCmd('No events file corresponding to %s run. '% self.run_name)
 
920
 
 
921
        input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe')
 
922
        output_file = pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')
 
923
        os.system('gunzip -c %s > %s' % (input_file, output_file))
 
924
        
 
925
        args.append(mode)
 
926
    
 
927
    def check_remove(self, args):
 
928
        """Check that the remove command is valid"""
 
929
 
 
930
        tmp_args = args[:]
 
931
 
 
932
        tag = [a[6:] for a in tmp_args if a.startswith('--tag=')]
 
933
        if tag:
 
934
            tag = tag[0]
 
935
            tmp_args.remove('--tag=%s' % tag)
 
936
 
 
937
 
 
938
        if len(tmp_args) == 0:
 
939
            self.help_remove()
 
940
            raise self.InvalidCmd('clean command require the name of the run to clean')
 
941
        elif len(tmp_args) == 1:
 
942
            return tmp_args[0], tag, ['all']
 
943
        else:
 
944
            for arg in tmp_args[1:]:
 
945
                if arg not in self._clean_mode:
 
946
                    self.help_remove()
 
947
                    raise self.InvalidCmd('%s is not a valid options for clean command'\
 
948
                                              % arg)
 
949
            return tmp_args[0], tag, tmp_args[1:]
 
950
 
 
951
    def check_plot(self, args):
 
952
        """Check the argument for the plot command
 
953
        plot run_name modes"""
 
954
 
 
955
        madir = self.options['madanalysis_path']
 
956
        td = self.options['td_path']
 
957
        
 
958
        if not madir or not td:
 
959
            logger.info('Retry to read configuration file to find madanalysis/td')
 
960
            self.set_configuration()
 
961
 
 
962
        madir = self.options['madanalysis_path']
 
963
        td = self.options['td_path']        
 
964
        
 
965
        if not madir:
 
966
            error_msg = 'No Madanalysis path correctly set.'
 
967
            error_msg += 'Please use the set command to define the path and retry.'
 
968
            error_msg += 'You can also define it in the configuration file.'
 
969
            raise self.InvalidCmd(error_msg)  
 
970
        if not  td:
 
971
            error_msg = 'No path to td directory correctly set.'
 
972
            error_msg += 'Please use the set command to define the path and retry.'
 
973
            error_msg += 'You can also define it in the configuration file.'
 
974
            raise self.InvalidCmd(error_msg)  
 
975
                     
 
976
        if len(args) == 0:
 
977
            if not hasattr(self, 'run_name') or not self.run_name:
 
978
                self.help_plot()
 
979
                raise self.InvalidCmd('No run name currently define. Please add this information.')             
 
980
            args.append('all')
 
981
            return
 
982
 
 
983
        
 
984
        if args[0] not in self._plot_mode:
 
985
            self.set_run_name(args[0], level='plot')
 
986
            del args[0]
 
987
            if len(args) == 0:
 
988
                args.append('all')
 
989
        elif not self.run_name:
 
990
            self.help_plot()
 
991
            raise self.InvalidCmd('No run name currently define. Please add this information.')                             
 
992
        
 
993
        for arg in args:
 
994
            if arg not in self._plot_mode and arg != self.run_name:
 
995
                 self.help_plot()
 
996
                 raise self.InvalidCmd('unknown options %s' % arg)        
 
997
    
 
998
    
 
999
    def check_pgs(self, arg):
 
1000
        """Check the argument for pythia command
 
1001
        syntax: pgs [NAME] 
 
1002
        Note that other option are already remove at this point
 
1003
        """
 
1004
        
 
1005
        # If not pythia-pgs path
 
1006
        if not self.options['pythia-pgs_path']:
 
1007
            logger.info('Retry to read configuration file to find pythia-pgs path')
 
1008
            self.set_configuration()
 
1009
      
 
1010
        if not self.options['pythia-pgs_path'] or not \
 
1011
            os.path.exists(pjoin(self.options['pythia-pgs_path'],'src')):
 
1012
            error_msg = 'No pythia-pgs path correctly set.'
 
1013
            error_msg += 'Please use the set command to define the path and retry.'
 
1014
            error_msg += 'You can also define it in the configuration file.'
 
1015
            raise self.InvalidCmd(error_msg)          
 
1016
        
 
1017
        tag = [a for a in arg if a.startswith('--tag=')]
 
1018
        if tag: 
 
1019
            arg.remove(tag[0])
 
1020
            tag = tag[0][6:]
 
1021
        
 
1022
        
 
1023
        if len(arg) == 0 and not self.run_name:
 
1024
            if self.results.lastrun:
 
1025
                arg.insert(0, self.results.lastrun)
 
1026
            else:
 
1027
                raise self.InvalidCmd('No run name currently define. Please add this information.')             
 
1028
        
 
1029
        if len(arg) == 1 and self.run_name == arg[0]:
 
1030
            arg.pop(0)
 
1031
        
 
1032
        if not len(arg) and \
 
1033
           not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')):
 
1034
            self.help_pgs()
 
1035
            raise self.InvalidCmd('''No file file pythia_events.hep currently available
 
1036
            Please specify a valid run_name''')
 
1037
        
 
1038
        lock = None                    
 
1039
        if len(arg) == 1:
 
1040
            prev_tag = self.set_run_name(arg[0], tag, 'pgs')
 
1041
            if  not os.path.exists(pjoin(self.me_dir,'Events',self.run_name,'%s_pythia_events.hep.gz' % prev_tag)):
 
1042
                raise self.InvalidCmd('No events file corresponding to %s run with tag %s. '% (self.run_name, prev_tag))
 
1043
            else:
 
1044
                input_file = pjoin(self.me_dir,'Events', self.run_name, '%s_pythia_events.hep.gz' % prev_tag)
 
1045
                output_file = pjoin(self.me_dir, 'Events', 'pythia_events.hep')
 
1046
                lock = cluster.asyncrone_launch('gunzip',stdout=open(output_file,'w'), 
 
1047
                                                    argument=['-c', input_file])
 
1048
 
 
1049
        else:
 
1050
            if tag: 
 
1051
                self.run_card['run_tag'] = tag
 
1052
            self.set_run_name(self.run_name, tag, 'pgs')
 
1053
        
 
1054
        return lock
 
1055
 
 
1056
    def check_delphes(self, arg):
 
1057
        """Check the argument for pythia command
 
1058
        syntax: delphes [NAME] 
 
1059
        Note that other option are already remove at this point
 
1060
        """
 
1061
        
 
1062
        # If not pythia-pgs path
 
1063
        if not self.options['delphes_path']:
 
1064
            logger.info('Retry to read configuration file to find delphes path')
 
1065
            self.set_configuration()
 
1066
      
 
1067
        if not self.options['delphes_path']:
 
1068
            error_msg = 'No delphes path correctly set.'
 
1069
            error_msg += 'Please use the set command to define the path and retry.'
 
1070
            error_msg += 'You can also define it in the configuration file.'
 
1071
            raise self.InvalidCmd(error_msg)  
 
1072
 
 
1073
        tag = [a for a in arg if a.startswith('--tag=')]
 
1074
        if tag: 
 
1075
            arg.remove(tag[0])
 
1076
            tag = tag[0][6:]
 
1077
            
 
1078
                  
 
1079
        if len(arg) == 0 and not self.run_name:
 
1080
            if self.results.lastrun:
 
1081
                arg.insert(0, self.results.lastrun)
 
1082
            else:
 
1083
                raise self.InvalidCmd('No run name currently define. Please add this information.')             
 
1084
        
 
1085
        if len(arg) == 1 and self.run_name == arg[0]:
 
1086
            arg.pop(0)
 
1087
        
 
1088
        if not len(arg) and \
 
1089
           not os.path.exists(pjoin(self.me_dir,'Events','pythia_events.hep')):
 
1090
            self.help_pgs()
 
1091
            raise self.InvalidCmd('''No file file pythia_events.hep currently available
 
1092
            Please specify a valid run_name''')
 
1093
        
 
1094
        lock = None                
 
1095
        if len(arg) == 1:
 
1096
            prev_tag = self.set_run_name(arg[0], tag, 'delphes')
 
1097
            if  not os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)):
 
1098
                raise self.InvalidCmd('No events file corresponding to %s run with tag %s.:%s '\
 
1099
                    % (self.run_name, prev_tag, 
 
1100
                       pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)))
 
1101
            else:
 
1102
                input_file = pjoin(self.me_dir,'Events', self.run_name, '%s_pythia_events.hep.gz' % prev_tag)
 
1103
                output_file = pjoin(self.me_dir, 'Events', 'pythia_events.hep')
 
1104
                lock = cluster.asyncrone_launch('gunzip',stdout=open(output_file,'w'), 
 
1105
                                                    argument=['-c', input_file])
 
1106
        else:
 
1107
            if tag:
 
1108
                self.run_card['run_tag'] = tag
 
1109
            self.set_run_name(self.run_name, tag, 'delphes')
 
1110
            
 
1111
        return lock               
 
1112
 
 
1113
    def check_display(self, args):
 
1114
        """check the validity of line
 
1115
        syntax: display XXXXX
 
1116
        """
 
1117
            
 
1118
        if len(args) < 1 or args[0] not in self._display_opts:
 
1119
            self.help_display()
 
1120
            raise self.InvalidCmd
 
1121
        
 
1122
        if args[0] == 'variable' and len(args) !=2:
 
1123
            raise self.InvalidCmd('variable need a variable name')
 
1124
 
 
1125
 
 
1126
 
 
1127
 
 
1128
 
 
1129
    def check_import(self, args):
 
1130
        """check the validity of line"""
 
1131
         
 
1132
        if not args:
 
1133
            self.help_import()
 
1134
            raise self.InvalidCmd('wrong \"import\" format')
 
1135
        
 
1136
        if args[0] != 'command':
 
1137
            args.insert(0,'command')
 
1138
        
 
1139
        
 
1140
        if not len(args) == 2 or not os.path.exists(args[1]):
 
1141
            raise self.InvalidCmd('PATH is mandatory for import command\n')
 
1142
        
 
1143
 
 
1144
#===============================================================================
 
1145
# CompleteForCmd
 
1146
#===============================================================================
 
1147
class CompleteForCmd(CheckValidForCmd):
 
1148
    """ The Series of help routine for the MadGraphCmd"""
 
1149
    
 
1150
    
 
1151
    def complete_add_time_of_flight(self, text, line, begidx, endidx):
 
1152
        "Complete command"
 
1153
       
 
1154
        args = self.split_arg(line[0:begidx], error=False)
 
1155
 
 
1156
        if len(args) == 1:
 
1157
            #return valid run_name
 
1158
            data = glob.glob(pjoin(self.me_dir, 'Events', '*','unweighted_events.lhe.gz'))
 
1159
            data = [n.rsplit('/',2)[1] for n in data]
 
1160
            return  self.list_completion(text, data + ['--threshold='], line)
 
1161
        elif args[-1].endswith(os.path.sep):
 
1162
            return self.path_completion(text,
 
1163
                                        os.path.join('.',*[a for a in args \
 
1164
                                                    if a.endswith(os.path.sep)]))
 
1165
        else:
 
1166
            return self.list_completion(text, ['--threshold='], line)
 
1167
    
 
1168
    def complete_banner_run(self, text, line, begidx, endidx):
 
1169
       "Complete the banner run command"
 
1170
       try:
 
1171
  
 
1172
        
 
1173
        args = self.split_arg(line[0:begidx], error=False)
 
1174
        
 
1175
        if args[-1].endswith(os.path.sep):
 
1176
            return self.path_completion(text,
 
1177
                                        os.path.join('.',*[a for a in args \
 
1178
                                                    if a.endswith(os.path.sep)]))        
 
1179
        
 
1180
        
 
1181
        if len(args) > 1:
 
1182
            # only options are possible
 
1183
            tags = glob.glob(pjoin(self.me_dir, 'Events' , args[1],'%s_*_banner.txt' % args[1]))
 
1184
            tags = ['%s' % os.path.basename(t)[len(args[1])+1:-11] for t in tags]
 
1185
 
 
1186
            if args[-1] != '--tag=':
 
1187
                tags = ['--tag=%s' % t for t in tags]
 
1188
            else:
 
1189
                return self.list_completion(text, tags)
 
1190
            return self.list_completion(text, tags +['--name=','-f'], line)
 
1191
        
 
1192
        # First argument
 
1193
        possibilites = {} 
 
1194
 
 
1195
        comp = self.path_completion(text, os.path.join('.',*[a for a in args \
 
1196
                                                    if a.endswith(os.path.sep)]))
 
1197
        if os.path.sep in line:
 
1198
            return comp
 
1199
        else:
 
1200
            possibilites['Path from ./'] = comp
 
1201
 
 
1202
        run_list =  glob.glob(pjoin(self.me_dir, 'Events', '*','*_banner.txt'))
 
1203
        run_list = [n.rsplit('/',2)[1] for n in run_list]
 
1204
        possibilites['RUN Name'] = self.list_completion(text, run_list)
 
1205
        
 
1206
        return self.deal_multiple_categories(possibilites)
 
1207
    
 
1208
        
 
1209
       except Exception, error:
 
1210
           print error
 
1211
    def complete_history(self, text, line, begidx, endidx):
 
1212
        "Complete the history command"
 
1213
 
 
1214
        args = self.split_arg(line[0:begidx], error=False)
 
1215
 
 
1216
        # Directory continuation
 
1217
        if args[-1].endswith(os.path.sep):
 
1218
            return self.path_completion(text,
 
1219
                                        os.path.join('.',*[a for a in args \
 
1220
                                                    if a.endswith(os.path.sep)]))
 
1221
 
 
1222
        if len(args) == 1:
 
1223
            return self.path_completion(text)
 
1224
        
 
1225
    def complete_open(self, text, line, begidx, endidx): 
 
1226
        """ complete the open command """
 
1227
 
 
1228
        args = self.split_arg(line[0:begidx])
 
1229
        
 
1230
        # Directory continuation
 
1231
        if os.path.sep in args[-1] + text:
 
1232
            return self.path_completion(text,
 
1233
                                    os.path.join('.',*[a for a in args if \
 
1234
                                                      a.endswith(os.path.sep)]))
 
1235
 
 
1236
        possibility = []
 
1237
        if self.me_dir:
 
1238
            path = self.me_dir
 
1239
            possibility = ['index.html']
 
1240
            if os.path.isfile(os.path.join(path,'README')):
 
1241
                possibility.append('README')
 
1242
            if os.path.isdir(os.path.join(path,'Cards')):
 
1243
                possibility += [f for f in os.listdir(os.path.join(path,'Cards')) 
 
1244
                                    if f.endswith('.dat')]
 
1245
            if os.path.isdir(os.path.join(path,'HTML')):
 
1246
                possibility += [f for f in os.listdir(os.path.join(path,'HTML')) 
 
1247
                                  if f.endswith('.html') and 'default' not in f]
 
1248
        else:
 
1249
            possibility.extend(['./','../'])
 
1250
        if os.path.exists('ME5_debug'):
 
1251
            possibility.append('ME5_debug')
 
1252
        if os.path.exists('MG5_debug'):
 
1253
            possibility.append('MG5_debug')
 
1254
        return self.list_completion(text, possibility)
 
1255
    
 
1256
    def complete_set(self, text, line, begidx, endidx):
 
1257
        "Complete the set command"
 
1258
 
 
1259
        args = self.split_arg(line[0:begidx])
 
1260
 
 
1261
        # Format
 
1262
        if len(args) == 1:
 
1263
            return self.list_completion(text, self._set_options + self.options.keys() )
 
1264
 
 
1265
        if len(args) == 2:
 
1266
            if args[1] == 'stdout_level':
 
1267
                return self.list_completion(text, ['DEBUG','INFO','WARNING','ERROR','CRITICAL'])
 
1268
            else:
 
1269
                first_set = ['None','True','False']
 
1270
                # directory names
 
1271
                second_set = [name for name in self.path_completion(text, '.', only_dirs = True)]
 
1272
                return self.list_completion(text, first_set + second_set)
 
1273
        elif len(args) >2 and args[-1].endswith(os.path.sep):
 
1274
                return self.path_completion(text,
 
1275
                        os.path.join('.',*[a for a in args if a.endswith(os.path.sep)]),
 
1276
                        only_dirs = True) 
 
1277
    
 
1278
    def complete_survey(self, text, line, begidx, endidx):
 
1279
        """ Complete the survey command """
 
1280
        
 
1281
        if line.endswith('nb_core=') and not text:
 
1282
            import multiprocessing
 
1283
            max = multiprocessing.cpu_count()
 
1284
            return [str(i) for i in range(2,max+1)]
 
1285
            
 
1286
        return  self.list_completion(text, self._run_options, line)
 
1287
    
 
1288
    complete_refine = complete_survey
 
1289
    complete_combine_events = complete_survey
 
1290
    complite_store = complete_survey
 
1291
    complete_generate_events = complete_survey
 
1292
    complete_create_gridpack = complete_survey
 
1293
    
 
1294
    def complete_generate_events(self, text, line, begidx, endidx):
 
1295
        """ Complete the generate events"""
 
1296
        
 
1297
        if line.endswith('nb_core=') and not text:
 
1298
            import multiprocessing
 
1299
            max = multiprocessing.cpu_count()
 
1300
            return [str(i) for i in range(2,max+1)]
 
1301
        if line.endswith('laststep=') and not text:
 
1302
            return ['parton','pythia','pgs','delphes']
 
1303
        elif '--laststep=' in line.split()[-1] and line and line[-1] != ' ':
 
1304
            return self.list_completion(text,['parton','pythia','pgs','delphes'],line)
 
1305
        
 
1306
        opts = self._run_options + self._generate_options
 
1307
        return  self.list_completion(text, opts, line)
 
1308
 
 
1309
    def complete_launch(self, *args, **opts):
 
1310
 
 
1311
        if self.ninitial == 1:
 
1312
            return self.complete_calculate_decay_widths(*args, **opts)
 
1313
        else:
 
1314
            return self.complete_generate_events(*args, **opts)
 
1315
 
 
1316
 
 
1317
    def complete_calculate_decay_widths(self, text, line, begidx, endidx):
 
1318
        """ Complete the calculate_decay_widths command"""
 
1319
        
 
1320
        if line.endswith('nb_core=') and not text:
 
1321
            import multiprocessing
 
1322
            max = multiprocessing.cpu_count()
 
1323
            return [str(i) for i in range(2,max+1)]
 
1324
        
 
1325
        opts = self._run_options + self._calculate_decay_options
 
1326
        return  self.list_completion(text, opts, line)
 
1327
 
 
1328
    def complete_multi_run(self, text, line, begidx, endidx):
 
1329
        """complete multi run command"""
 
1330
        
 
1331
        args = self.split_arg(line[0:begidx], error=False)
 
1332
        if len(args) == 1:
 
1333
            data = [str(i) for i in range(0,20)]
 
1334
            return  self.list_completion(text, data, line)
 
1335
        
 
1336
        if line.endswith('run=') and not text:
 
1337
            return ['parton','pythia','pgs','delphes']
 
1338
        elif '--laststep=' in line.split()[-1] and line and line[-1] != ' ':
 
1339
            return self.list_completion(text,['parton','pythia','pgs','delphes'],line)
 
1340
        
 
1341
        opts = self._run_options + self._generate_options
 
1342
        return  self.list_completion(text, opts, line)
 
1343
        
 
1344
        
 
1345
        
 
1346
        if line.endswith('nb_core=') and not text:
 
1347
            import multiprocessing
 
1348
            max = multiprocessing.cpu_count()
 
1349
            return [str(i) for i in range(2,max+1)]
 
1350
        opts = self._run_options + self._generate_options
 
1351
        return  self.list_completion(text, opts, line)
 
1352
    
 
1353
    def complete_plot(self, text, line, begidx, endidx):
 
1354
        """ Complete the plot command """
 
1355
        
 
1356
        args = self.split_arg(line[0:begidx], error=False)
 
1357
        if len(args) > 1:
 
1358
            return self.list_completion(text, self._plot_mode)
 
1359
        else:
 
1360
            return self.list_completion(text, self._plot_mode + self.results.keys())
 
1361
        
 
1362
    def complete_remove(self, text, line, begidx, endidx):
 
1363
        """Complete the remove command """
 
1364
     
 
1365
        args = self.split_arg(line[0:begidx], error=False)
 
1366
        if len(args) > 1 and (text.startswith('--t')):
 
1367
            run = args[1]
 
1368
            tags = ['--tag=%s' % tag['tag'] for tag in self.results[run]]
 
1369
            return self.list_completion(text, tags)
 
1370
        elif len(args) > 1 and '--' == args[-1]:
 
1371
            run = args[1]
 
1372
            tags = ['tag=%s' % tag['tag'] for tag in self.results[run]]
 
1373
            return self.list_completion(text, tags)
 
1374
        elif len(args) > 1 and '--tag=' == args[-1]:
 
1375
            run = args[1]
 
1376
            tags = [tag['tag'] for tag in self.results[run]]
 
1377
            return self.list_completion(text, tags)
 
1378
        elif len(args) > 1:
 
1379
            return self.list_completion(text, self._clean_mode + ['-f','--tag='])
 
1380
        else:
 
1381
            data = glob.glob(pjoin(self.me_dir, 'Events','*','*_banner.txt'))
 
1382
            data = [n.rsplit('/',2)[1] for n in data]
 
1383
            return self.list_completion(text, ['all'] + data)
 
1384
         
 
1385
        
 
1386
    def complete_pythia(self,text, line, begidx, endidx):
 
1387
        "Complete the pythia command"
 
1388
        args = self.split_arg(line[0:begidx], error=False)
 
1389
 
 
1390
        if len(args) == 1:
 
1391
            #return valid run_name
 
1392
            data = glob.glob(pjoin(self.me_dir, 'Events', '*','unweighted_events.lhe.gz'))
 
1393
            data = [n.rsplit('/',2)[1] for n in data]
 
1394
            tmp1 =  self.list_completion(text, data)
 
1395
            if not self.run_name:
 
1396
                return tmp1
 
1397
            else:
 
1398
                tmp2 = self.list_completion(text, self._run_options + ['-f', 
 
1399
                                                '--no_default', '--tag='], line)
 
1400
                return tmp1 + tmp2
 
1401
        elif line[-1] != '=':
 
1402
            return self.list_completion(text, self._run_options + ['-f', 
 
1403
                                                 '--no_default','--tag='], line)
 
1404
 
 
1405
    def complete_pgs(self,text, line, begidx, endidx):
 
1406
        "Complete the pythia command"
 
1407
        args = self.split_arg(line[0:begidx], error=False) 
 
1408
        if len(args) == 1:
 
1409
            #return valid run_name
 
1410
            data = glob.glob(pjoin(self.me_dir, 'Events', '*', '*_pythia_events.hep.gz'))
 
1411
            data = [n.rsplit('/',2)[1] for n in data]
 
1412
            tmp1 =  self.list_completion(text, data)
 
1413
            if not self.run_name:
 
1414
                return tmp1
 
1415
            else:
 
1416
                tmp2 = self.list_completion(text, self._run_options + ['-f', 
 
1417
                                                '--tag=' ,'--no_default'], line)
 
1418
                return tmp1 + tmp2        
 
1419
        else:
 
1420
            return self.list_completion(text, self._run_options + ['-f', 
 
1421
                                                 '--tag=','--no_default'], line)
 
1422
 
 
1423
    complete_delphes = complete_pgs        
 
1424
 
 
1425
 
 
1426
 
 
1427
 
 
1428
#===============================================================================
 
1429
# MadEventCmd
 
1430
#===============================================================================
 
1431
class MadEventCmd(CmdExtended, HelpToCmd, CompleteForCmd, common_run.CommonRunCmd):
 
1432
    """The command line processor of MadGraph"""    
 
1433
    
 
1434
    # Truth values
 
1435
    true = ['T','.true.',True,'true']
 
1436
    # Options and formats available
 
1437
    _run_options = ['--cluster','--multicore','--nb_core=','--nb_core=2', '-c', '-m']
 
1438
    _generate_options = ['-f', '--laststep=parton', '--laststep=pythia', '--laststep=pgs', '--laststep=delphes']
 
1439
    _calculate_decay_options = ['-f', '--accuracy=0.']
 
1440
    _set_options = ['stdout_level','fortran_compiler','timeout']
 
1441
    _plot_mode = ['all', 'parton','pythia','pgs','delphes','channel', 'banner']
 
1442
    _clean_mode = _plot_mode
 
1443
    _display_opts = ['run_name', 'options', 'variable']
 
1444
    # survey options, dict from name to type, default value, and help text
 
1445
    _survey_options = {'points':('int', 1000,'Number of points for first iteration'),
 
1446
                       'iterations':('int', 5, 'Number of iterations'),
 
1447
                       'accuracy':('float', 0.1, 'Required accuracy'),
 
1448
                       'gridpack':('str', '.false.', 'Gridpack generation')}
 
1449
    # Variables to store object information
 
1450
    true = ['T','.true.',True,'true', 1, '1']
 
1451
    web = False
 
1452
    prompt = 'MGME5>'
 
1453
    cluster_mode = 0
 
1454
    queue  = 'madgraph'
 
1455
    nb_core = None
 
1456
    
 
1457
    next_possibility = {
 
1458
        'start': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]',
 
1459
                  'calculate_decay_widths [OPTIONS]',
 
1460
                  'help generate_events'],
 
1461
        'generate_events': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]', 'pythia', 'pgs','delphes'],
 
1462
        'calculate_decay_widths': ['calculate_decay_widths [OPTIONS]',
 
1463
                                   'generate_events [OPTIONS]'],
 
1464
        'multi_run': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'],
 
1465
        'survey': ['refine'],
 
1466
        'refine': ['combine_events'],
 
1467
        'combine_events': ['store'],
 
1468
        'store': ['pythia'],
 
1469
        'pythia': ['pgs', 'delphes'],
 
1470
        'pgs': ['generate_events [OPTIONS]', 'multi_run [OPTIONS]'],
 
1471
        'delphes' : ['generate_events [OPTIONS]', 'multi_run [OPTIONS]']
 
1472
    }
 
1473
    
 
1474
    ############################################################################
 
1475
    def __init__(self, me_dir = None, options={}, *completekey, **stdin):
 
1476
        """ add information to the cmd """
 
1477
 
 
1478
        CmdExtended.__init__(self, me_dir, options, *completekey, **stdin)
 
1479
        #common_run.CommonRunCmd.__init__(self, me_dir, options)
 
1480
        
 
1481
 
 
1482
        self.mode = 'madevent'
 
1483
        self.nb_refine=0
 
1484
        if self.web:
 
1485
            os.system('touch %s' % pjoin(self.me_dir,'Online'))
 
1486
 
 
1487
        
 
1488
        # load the current status of the directory
 
1489
        if os.path.exists(pjoin(self.me_dir,'HTML','results.pkl')):
 
1490
            self.results = save_load_object.load_from_file(pjoin(self.me_dir,'HTML','results.pkl'))
 
1491
            self.results.resetall(self.me_dir)
 
1492
        else:
 
1493
            model = self.find_model_name()
 
1494
            process = self.process # define in find_model_name
 
1495
            self.results = gen_crossxhtml.AllResults(model, process, self.me_dir)
 
1496
        self.results.def_web_mode(self.web)
 
1497
        gen_crossxhtml.GenCardHTML(self.results)
 
1498
        
 
1499
        self.configured = 0 # time for reading the card
 
1500
        self._options = {} # for compatibility with extended_cmd
 
1501
    
 
1502
    def pass_in_web_mode(self):
 
1503
        """configure web data"""
 
1504
        self.web = True
 
1505
        self.results.def_web_mode(True)
 
1506
        self.force = True
 
1507
 
 
1508
    ############################################################################            
 
1509
    def check_output_type(self, path):
 
1510
        """ Check that the output path is a valid madevent directory """
 
1511
        
 
1512
        bin_path = os.path.join(path,'bin')
 
1513
        if os.path.isfile(os.path.join(bin_path,'generate_events')):
 
1514
            return True
 
1515
        else: 
 
1516
            return False
 
1517
            
 
1518
    ############################################################################
 
1519
    def do_add_time_of_flight(self, line):
 
1520
 
 
1521
        args = self.split_arg(line)
 
1522
        #check the validity of the arguments and reformat args
 
1523
        self.check_add_time_of_flight(args)
 
1524
        
 
1525
        event_path, threshold = args
 
1526
        #gunzip the file
 
1527
        if event_path.endswith('.gz'):
 
1528
            need_zip = True
 
1529
            subprocess.call(['gunzip', event_path])
 
1530
            event_path = event_path[:-3]
 
1531
        else:
 
1532
            need_zip = False
 
1533
            
 
1534
        import random
 
1535
        try:
 
1536
            import madgraph.various.lhe_parser as lhe_parser
 
1537
        except:
 
1538
            import internal.lhe_parser as lhe_parser 
 
1539
            
 
1540
        logger.info('Add time of flight information on file %s' % event_path)
 
1541
        lhe = lhe_parser.EventFile(event_path)
 
1542
        output = open('%s_2vertex.lhe' % event_path, 'w')
 
1543
        #write the banner to the output file
 
1544
        output.write(lhe.banner)
 
1545
 
 
1546
        # get the associate param_card
 
1547
        begin_param = lhe.banner.find('<slha>')
 
1548
        end_param = lhe.banner.find('</slha>')
 
1549
        param_card = lhe.banner[begin_param+6:end_param].split('\n')
 
1550
        param_card = check_param_card.ParamCard(param_card)
 
1551
 
 
1552
        cst = 6.58211915e-25
 
1553
        # Loop over all events
 
1554
        for event in lhe:
 
1555
            for particle in event:
 
1556
                id = particle.pid
 
1557
                width = param_card['decay'].get((abs(id),)).value
 
1558
                if width:
 
1559
                    vtim = random.expovariate(width/cst)
 
1560
                    if vtim > threshold:
 
1561
                        particle.vtim = vtim
 
1562
            #write this modify event
 
1563
            output.write(str(event))
 
1564
        output.write('</LesHouchesEvents>\n')
 
1565
        output.close()
 
1566
        
 
1567
        files.mv('%s_2vertex.lhe' % event_path, event_path)
 
1568
        
 
1569
        if need_zip:
 
1570
            subprocess.call(['gzip', event_path])
 
1571
        
 
1572
    ############################################################################
 
1573
    def do_banner_run(self, line): 
 
1574
        """Make a run from the banner file"""
 
1575
        
 
1576
        args = self.split_arg(line)
 
1577
        #check the validity of the arguments
 
1578
        self.check_banner_run(args)    
 
1579
                     
 
1580
        # Remove previous cards
 
1581
        for name in ['delphes_trigger.dat', 'delphes_card.dat',
 
1582
                     'pgs_card.dat', 'pythia_card.dat']:
 
1583
            try:
 
1584
                os.remove(pjoin(self.me_dir, 'Cards', name))
 
1585
            except Exception:
 
1586
                pass
 
1587
            
 
1588
        banner_mod.split_banner(args[0], self.me_dir, proc_card=False)
 
1589
        
 
1590
        # Check if we want to modify the run
 
1591
        if not self.force:
 
1592
            ans = self.ask('Do you want to modify the Cards?', 'n', ['y','n'])
 
1593
            if ans == 'n':
 
1594
                self.force = True
 
1595
        
 
1596
        # Call Generate events
 
1597
        self.exec_cmd('generate_events %s %s' % (self.run_name, self.force and '-f' or ''))
 
1598
 
 
1599
 
 
1600
 
 
1601
    ############################################################################
 
1602
    def do_display(self, line, output=sys.stdout):
 
1603
        """Display current internal status"""
 
1604
 
 
1605
        args = self.split_arg(line)
 
1606
        #check the validity of the arguments
 
1607
        self.check_display(args)
 
1608
 
 
1609
        if args[0] == 'run_name':
 
1610
            #return valid run_name
 
1611
            data = glob.glob(pjoin(self.me_dir, 'Events', '*','*_banner.txt'))
 
1612
            data = [n.rsplit('/',2)[1:] for n in data]
 
1613
            
 
1614
            if data:
 
1615
                out = {}
 
1616
                for name, tag in data:
 
1617
                    tag = tag[len(name)+1:-11]
 
1618
                    if name in out:
 
1619
                        out[name].append(tag)
 
1620
                    else:
 
1621
                        out[name] = [tag]
 
1622
                print 'the runs available are:'
 
1623
                for run_name, tags in out.items():
 
1624
                    print '  run: %s' % run_name
 
1625
                    print '       tags: ', 
 
1626
                    print ', '.join(tags)
 
1627
            else:
 
1628
                print 'No run detected.'
 
1629
                
 
1630
        elif  args[0] == 'options':
 
1631
            outstr = "                              Run Options    \n"
 
1632
            outstr += "                              -----------    \n"
 
1633
            for key, default in self.options_madgraph.items():
 
1634
                value = self.options[key]
 
1635
                if value == default:
 
1636
                    outstr += "  %25s \t:\t%s\n" % (key,value)
 
1637
                else:
 
1638
                    outstr += "  %25s \t:\t%s (user set)\n" % (key,value)
 
1639
            outstr += "\n"
 
1640
            outstr += "                         MadEvent Options    \n"
 
1641
            outstr += "                         ----------------    \n"
 
1642
            for key, default in self.options_madevent.items():
 
1643
                value = self.options[key]
 
1644
                if value == default:
 
1645
                    outstr += "  %25s \t:\t%s\n" % (key,value)
 
1646
                else:
 
1647
                    outstr += "  %25s \t:\t%s (user set)\n" % (key,value)  
 
1648
            outstr += "\n"                 
 
1649
            outstr += "                      Configuration Options    \n"
 
1650
            outstr += "                      ---------------------    \n"
 
1651
            for key, default in self.options_configuration.items():
 
1652
                value = self.options[key]
 
1653
                if value == default:
 
1654
                    outstr += "  %25s \t:\t%s\n" % (key,value)
 
1655
                else:
 
1656
                    outstr += "  %25s \t:\t%s (user set)\n" % (key,value)
 
1657
            output.write(outstr)
 
1658
        else:
 
1659
            super(MadEventCmd, self).do_display(line, output)
 
1660
 
 
1661
    def do_save(self, line, check=True, to_keep={}):
 
1662
        """Not in help: Save information to file"""  
 
1663
 
 
1664
        args = self.split_arg(line)
 
1665
        # Check argument validity
 
1666
        if check:
 
1667
            self.check_save(args)
 
1668
        
 
1669
        if args[0] == 'options':
 
1670
            # First look at options which should be put in MG5DIR/input
 
1671
            to_define = {}
 
1672
            for key, default in self.options_configuration.items():
 
1673
                if self.options[key] != self.options_configuration[key]:
 
1674
                    to_define[key] = self.options[key]
 
1675
 
 
1676
            if not '--auto' in args:
 
1677
                for key, default in self.options_madevent.items():
 
1678
                    if self.options[key] != self.options_madevent[key]:
 
1679
                        to_define[key] = self.options[key]
 
1680
            
 
1681
            if '--all' in args:
 
1682
                for key, default in self.options_madgraph.items():
 
1683
                    if self.options[key] != self.options_madgraph[key]:
 
1684
                        to_define[key] = self.options[key]
 
1685
            elif not '--auto' in args:
 
1686
                for key, default in self.options_madgraph.items():
 
1687
                    if self.options[key] != self.options_madgraph[key]:
 
1688
                        logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \
 
1689
                                    % (key,self.options_madgraph[key]) )
 
1690
                        logger.info('If you want to make this value the default for future session, you can run \'save options --all\'')
 
1691
            if len(args) >1 and not args[1].startswith('--'):
 
1692
                filepath = args[1]
 
1693
            else:
 
1694
                filepath = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
 
1695
            basefile = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
 
1696
            basedir = self.me_dir
 
1697
            
 
1698
            if to_keep:
 
1699
                to_define = to_keep
 
1700
            self.write_configuration(filepath, basefile, basedir, to_define)
 
1701
  
 
1702
    ############################################################################
 
1703
    def do_import(self, line):
 
1704
        """Advanced commands: Import command files"""
 
1705
 
 
1706
        args = self.split_arg(line)
 
1707
        # Check argument's validity
 
1708
        self.check_import(args)
 
1709
        
 
1710
        # Execute the card
 
1711
        self.import_command_file(args[1])  
 
1712
 
 
1713
 
 
1714
    def post_set(self, stop, line):
 
1715
        """Check if we need to save this in the option file"""
 
1716
        try:
 
1717
            args = self.split_arg(line)
 
1718
            # Check the validity of the arguments
 
1719
            self.check_set(args)
 
1720
            
 
1721
            if args[0] in self.options_configuration and '--no_save' not in args:
 
1722
                self.exec_cmd('save options --auto')
 
1723
            elif args[0] in self.options_madevent:
 
1724
                logger.info('This option will be the default in any output that you are going to create in this session.')
 
1725
                logger.info('In order to keep this changes permanent please run \'save options\'')
 
1726
            return stop
 
1727
        except self.InvalidCmd:
 
1728
            return stop
 
1729
 
 
1730
    ############################################################################
 
1731
    def do_generate_events(self, line):
 
1732
        """Main commands: launch the full chain """
 
1733
 
 
1734
 
 
1735
        
 
1736
        
 
1737
        args = self.split_arg(line)
 
1738
        # Check argument's validity
 
1739
        mode = self.check_generate_events(args)
 
1740
        self.ask_run_configuration(mode)
 
1741
        if not args:
 
1742
            # No run name assigned -> assigned one automaticaly 
 
1743
            self.set_run_name(self.find_available_run_name(self.me_dir), None, 'parton')
 
1744
        else:
 
1745
            self.set_run_name(args[0], None, 'parton', True)
 
1746
            args.pop(0)
 
1747
            
 
1748
        if self.run_card['gridpack'] in self.true:        
 
1749
            # Running gridpack warmup
 
1750
            gridpack_opts=[('accuracy', 0.01),
 
1751
                           ('points', 2000),
 
1752
                           ('iterations',8),
 
1753
                           ('gridpack','.true.')]
 
1754
            logger.info('Generating gridpack with run name %s' % self.run_name)
 
1755
            self.exec_cmd('survey  %s %s' % \
 
1756
                          (self.run_name,
 
1757
                           " ".join(['--' + opt + '=' + str(val) for (opt,val) \
 
1758
                                     in gridpack_opts])),
 
1759
                          postcmd=False)
 
1760
            self.exec_cmd('combine_events', postcmd=False)
 
1761
            self.exec_cmd('store_events', postcmd=False)
 
1762
            self.exec_cmd('create_gridpack', postcmd=False)
 
1763
        else:
 
1764
            # Regular run mode
 
1765
            logger.info('Generating %s events with run name %s' %
 
1766
                        (self.run_card['nevents'], self.run_name))
 
1767
        
 
1768
            self.exec_cmd('survey  %s %s' % (self.run_name,' '.join(args)),
 
1769
                          postcmd=False)
 
1770
            if not float(self.results.current['cross']):
 
1771
                # Zero cross-section. Try to guess why
 
1772
                text = '''Survey return zero cross section. 
 
1773
   Typical reasons are the following:
 
1774
   1) A massive s-channel particle has a width set to zero.
 
1775
   2) The pdf are zero for at least one of the initial state particles
 
1776
      or you are using maxjetflavor=4 for initial state b:s.
 
1777
   3) The cuts are too strong.
 
1778
   Please check/correct your param_card and/or your run_card.'''
 
1779
                logger_stderr.critical(text)
 
1780
                raise ZeroResult('See https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/FAQ-General-14')
 
1781
            nb_event = self.run_card['nevents']
 
1782
            self.exec_cmd('refine %s' % nb_event, postcmd=False)
 
1783
            self.exec_cmd('refine %s' % nb_event, postcmd=False)
 
1784
            self.exec_cmd('combine_events', postcmd=False)
 
1785
            self.print_results_in_shell(self.results.current)
 
1786
            self.create_plot('parton')
 
1787
            self.exec_cmd('store_events', postcmd=False)
 
1788
            self.exec_cmd('decay_events -from_cards', postcmd=False)
 
1789
            self.exec_cmd('pythia --no_default', postcmd=False, printcmd=False)
 
1790
            # pythia launches pgs/delphes if needed
 
1791
            self.store_result()
 
1792
            
 
1793
    
 
1794
    def do_launch(self, line, *args, **opt):
 
1795
        """Main commands:exec generate_events for 2>N and calculate_width for 1>N"""
 
1796
        if self.ninitial == 1:
 
1797
            self.do_calculate_decay_widths(line, *args, **opt)
 
1798
        else:
 
1799
            self.do_generate_events(line, *args, **opt)
 
1800
            
 
1801
    def print_results_in_shell(self, data):
 
1802
        """Have a nice results prints in the shell,
 
1803
        data should be of type: gen_crossxhtml.OneTagResults"""
 
1804
        if not data:
 
1805
            return
 
1806
        logger.info("  === Results Summary for run: %s tag: %s ===\n" % (data['run_name'],data['tag']))
 
1807
        if self.ninitial == 1:
 
1808
            logger.info("     Width :   %.4g +- %.4g GeV" % (data['cross'], data['error']))
 
1809
        else:
 
1810
            logger.info("     Cross-section :   %.4g +- %.4g pb" % (data['cross'], data['error']))
 
1811
        logger.info("     Nb of events :  %s" % data['nb_event'] )
 
1812
        if data['cross_pythia'] and data['nb_event_pythia']:
 
1813
            if self.ninitial == 1:
 
1814
                logger.info("     Matched Width :   %.4g +- %.4g GeV" % (data['cross_pythia'], data['error_pythia']))
 
1815
            else:
 
1816
                logger.info("     Matched Cross-section :   %.4g +- %.4g pb" % (data['cross_pythia'], data['error_pythia']))            
 
1817
            logger.info("     Nb of events after Matching :  %s" % data['nb_event_pythia'])
 
1818
        logger.info(" " )
 
1819
    
 
1820
    ############################################################################      
 
1821
    def do_calculate_decay_widths(self, line):
 
1822
        """Main commands:launch decay width calculation and automatic inclusion of
 
1823
        calculated widths and BRs in the param_card."""
 
1824
 
 
1825
        
 
1826
        args = self.split_arg(line)
 
1827
        # Check argument's validity
 
1828
        accuracy = self.check_calculate_decay_widths(args)
 
1829
        self.ask_run_configuration('parton')
 
1830
        if not args:
 
1831
            # No run name assigned -> assigned one automaticaly 
 
1832
            self.set_run_name(self.find_available_run_name(self.me_dir))
 
1833
        else:
 
1834
            self.set_run_name(args[0], reload_card=True)
 
1835
            args.pop(0)
 
1836
        
 
1837
        # Running gridpack warmup
 
1838
        opts=[('accuracy', accuracy), # default 0.01
 
1839
              ('points', 1000),
 
1840
              ('iterations',9)]
 
1841
 
 
1842
        logger.info('Calculating decay widths with run name %s' % self.run_name)
 
1843
        
 
1844
        self.exec_cmd('survey  %s %s' % \
 
1845
                      (self.run_name,
 
1846
                       " ".join(['--' + opt + '=' + str(val) for (opt,val) \
 
1847
                                 in opts])),
 
1848
                      postcmd=False)
 
1849
        self.exec_cmd('combine_events', postcmd=False)
 
1850
        self.exec_cmd('store_events', postcmd=False)
 
1851
        
 
1852
        self.collect_decay_widths()
 
1853
        self.update_status('calculate_decay_widths done', 
 
1854
                                                 level='parton', makehtml=False)   
 
1855
 
 
1856
    
 
1857
    ############################################################################
 
1858
    def collect_decay_widths(self):
 
1859
        """ Collect the decay widths and calculate BRs for all particles, and put 
 
1860
        in param_card form. 
 
1861
        """
 
1862
        
 
1863
        particle_dict = {} # store the results
 
1864
        run_name = self.run_name
 
1865
 
 
1866
        # Looping over the Subprocesses
 
1867
        for P_path in SubProcesses.get_subP(self.me_dir):
 
1868
            ids = SubProcesses.get_subP_ids(P_path)
 
1869
            # due to grouping we need to compute the ratio factor for the 
 
1870
            # ungroup resutls (that we need here). Note that initial particles
 
1871
            # grouping are not at the same stage as final particle grouping
 
1872
            nb_output = len(ids) / (len(set([p[0] for p in ids])))
 
1873
            results = open(pjoin(P_path, run_name + '_results.dat')).read().split('\n')[0]
 
1874
            result = float(results.strip().split(' ')[0])
 
1875
            for particles in ids:
 
1876
                try:
 
1877
                    particle_dict[particles[0]].append([particles[1:], result/nb_output])
 
1878
                except KeyError:
 
1879
                    particle_dict[particles[0]] = [[particles[1:], result/nb_output]]
 
1880
    
 
1881
        self.update_width_in_param_card(particle_dict,
 
1882
                        initial = pjoin(self.me_dir, 'Cards', 'param_card.dat'),
 
1883
                        output=pjoin(self.me_dir, 'Events', run_name, "param_card.dat"))
 
1884
    
 
1885
    @staticmethod
 
1886
    def update_width_in_param_card(decay_info, initial, output=None):
 
1887
        # Open the param_card.dat and insert the calculated decays and BRs
 
1888
        
 
1889
        if not output:
 
1890
            output = initial
 
1891
        
 
1892
        param_card_file = open(initial)
 
1893
        param_card = param_card_file.read().split('\n')
 
1894
        param_card_file.close()
 
1895
 
 
1896
        decay_lines = []
 
1897
        line_number = 0
 
1898
        # Read and remove all decays from the param_card                     
 
1899
        while line_number < len(param_card):
 
1900
            line = param_card[line_number]
 
1901
            if line.lower().startswith('decay'):
 
1902
                # Read decay if particle in decay_info 
 
1903
                # DECAY  6   1.455100e+00                                    
 
1904
                line = param_card.pop(line_number)
 
1905
                line = line.split()
 
1906
                particle = 0
 
1907
                if int(line[1]) not in decay_info:
 
1908
                    try: # If formatting is wrong, don't want this particle
 
1909
                        particle = int(line[1])
 
1910
                        width = float(line[2])
 
1911
                    except Exception:
 
1912
                        particle = 0
 
1913
                # Read BRs for this decay
 
1914
                line = param_card[line_number]
 
1915
                while line.startswith('#') or line.startswith(' '):
 
1916
                    line = param_card.pop(line_number)
 
1917
                    if not particle or line.startswith('#'):
 
1918
                        line=param_card[line_number]
 
1919
                        continue
 
1920
                    #    6.668201e-01   3    5  2  -1
 
1921
                    line = line.split()
 
1922
                    try: # Remove BR if formatting is wrong
 
1923
                        partial_width = float(line[0])*width
 
1924
                        decay_products = [int(p) for p in line[2:2+int(line[1])]]
 
1925
                    except Exception:
 
1926
                        line=param_card[line_number]
 
1927
                        continue
 
1928
                    try:
 
1929
                        decay_info[particle].append([decay_products, partial_width])
 
1930
                    except KeyError:
 
1931
                        decay_info[particle] = [[decay_products, partial_width]]
 
1932
                    line=param_card[line_number]
 
1933
                if particle and particle not in decay_info:
 
1934
                    # No decays given, only total width       
 
1935
                    decay_info[particle] = [[[], width]]
 
1936
            else: # Not decay                              
 
1937
                line_number += 1
 
1938
        # Clean out possible remaining comments at the end of the card
 
1939
        while not param_card[-1] or param_card[-1].startswith('#'):
 
1940
            param_card.pop(-1)
 
1941
 
 
1942
        # Append calculated and read decays to the param_card                                   
 
1943
        param_card.append("#\n#*************************")
 
1944
        param_card.append("#      Decay widths      *")
 
1945
        param_card.append("#*************************")
 
1946
        for key in sorted(decay_info.keys()):
 
1947
            width = sum([r for p,r in decay_info[key]])
 
1948
            param_card.append("#\n#      PDG        Width")
 
1949
            param_card.append("DECAY  %i   %e" % (key, width.real))
 
1950
            if not width:
 
1951
                continue
 
1952
            if decay_info[key][0][0]:
 
1953
                param_card.append("#  BR             NDA  ID1    ID2   ...")
 
1954
                brs = [[(val[1]/width).real, val[0]] for val in decay_info[key] if val[1]]
 
1955
                for val in sorted(brs, reverse=True):
 
1956
                    param_card.append("   %e   %i    %s # %s" % 
 
1957
                                      (val[0].real, len(val[1]),
 
1958
                                       "  ".join([str(v) for v in val[1]]),
 
1959
                                       val[0] * width
 
1960
                                       ))
 
1961
        decay_table = open(output, 'w')
 
1962
        decay_table.write("\n".join(param_card) + "\n")
 
1963
        logger.info("Results written to %s" %  output)
 
1964
 
 
1965
    ############################################################################
 
1966
    def do_multi_run(self, line):
 
1967
        
 
1968
        args = self.split_arg(line)
 
1969
        # Check argument's validity
 
1970
        mode = self.check_multi_run(args)
 
1971
        nb_run = args.pop(0)
 
1972
        if nb_run == 1:
 
1973
            logger.warn("'multi_run 1' command is not optimal. Think of using generate_events instead")
 
1974
        self.ask_run_configuration(mode)
 
1975
        main_name = self.run_name
 
1976
 
 
1977
 
 
1978
        
 
1979
        
 
1980
        
 
1981
        crossoversig = 0
 
1982
        inv_sq_err = 0
 
1983
        nb_event = 0
 
1984
        for i in range(nb_run):
 
1985
            self.nb_refine = 0
 
1986
            self.exec_cmd('generate_events %s_%s -f' % (main_name, i), postcmd=False)
 
1987
            # Update collected value
 
1988
            nb_event += int(self.results[self.run_name][-1]['nb_event'])  
 
1989
            self.results.add_detail('nb_event', nb_event , run=main_name)            
 
1990
            cross = self.results[self.run_name][-1]['cross']
 
1991
            error = self.results[self.run_name][-1]['error'] + 1e-99
 
1992
            crossoversig+=cross/error**2
 
1993
            inv_sq_err+=1.0/error**2
 
1994
            self.results[main_name][-1]['cross'] = crossoversig/inv_sq_err
 
1995
            self.results[main_name][-1]['error'] = math.sqrt(1.0/inv_sq_err)
 
1996
        self.results.def_current(main_name)
 
1997
        self.run_name = main_name
 
1998
        self.update_status("Merging LHE files", level='parton')
 
1999
        try:
 
2000
            os.mkdir(pjoin(self.me_dir,'Events', self.run_name))
 
2001
        except Exception:
 
2002
            pass
 
2003
        os.system('%(bin)s/merge.pl %(event)s/%(name)s_*/unweighted_events.lhe.gz %(event)s/%(name)s/unweighted_events.lhe.gz %(event)s/%(name)s_banner.txt' 
 
2004
                  % {'bin': self.dirbin, 'event': pjoin(self.me_dir,'Events'),
 
2005
                     'name': self.run_name})
 
2006
 
 
2007
        eradir = self.options['exrootanalysis_path']
 
2008
        if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter')):
 
2009
            self.update_status("Create Root file", level='parton')
 
2010
            os.system('gunzip %s/%s/unweighted_events.lhe.gz' % 
 
2011
                                  (pjoin(self.me_dir,'Events'), self.run_name))
 
2012
            self.create_root_file('%s/unweighted_events.lhe' % self.run_name,
 
2013
                                  '%s/unweighted_events.root' % self.run_name)
 
2014
            
 
2015
        
 
2016
        self.create_plot('parton', '%s/%s/unweighted_events.lhe' %
 
2017
                         (pjoin(self.me_dir, 'Events'),self.run_name),
 
2018
                         pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html')
 
2019
                         )
 
2020
        
 
2021
        os.system('gzip -f %s/%s/unweighted_events.lhe' % 
 
2022
                                  (pjoin(self.me_dir, 'Events'), self.run_name))
 
2023
 
 
2024
        self.update_status('', level='parton')
 
2025
        self.print_results_in_shell(self.results.current)   
 
2026
        
 
2027
 
 
2028
    ############################################################################      
 
2029
    def do_treatcards(self, line):
 
2030
        """Advanced commands: create .inc files from param_card.dat/run_card.dat"""
 
2031
 
 
2032
        args = self.split_arg(line)
 
2033
        mode,  opt  = self.check_treatcards(args)
 
2034
        
 
2035
        #check if no 'Auto' are present in the file
 
2036
        self.check_param_card(pjoin(self.me_dir, 'Cards','param_card.dat'))
 
2037
        
 
2038
        
 
2039
        if mode in ['run', 'all']:
 
2040
            if not hasattr(self, 'run_card'):
 
2041
                run_card = banner_mod.RunCard(opt['run_card'])
 
2042
            else:
 
2043
                run_card = self.run_card
 
2044
            run_card.write_include_file(pjoin(opt['output_dir'],'run_card.inc'))
 
2045
        
 
2046
        if mode in ['param', 'all']:
 
2047
            model = self.find_model_name()
 
2048
            if model == 'mssm' or model.startswith('mssm-'):
 
2049
                if not '--param_card=' in line:
 
2050
                    param_card = pjoin(self.me_dir, 'Cards','param_card.dat')
 
2051
                    mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat')
 
2052
                    check_param_card.convert_to_mg5card(param_card, mg5_param)
 
2053
                    check_param_card.check_valid_param_card(mg5_param)
 
2054
                    opt['param_card'] = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat')            
 
2055
            
 
2056
            logger.debug('write compile file for card: %s' % opt['param_card']) 
 
2057
            param_card = check_param_card.ParamCard(opt['param_card'])
 
2058
            outfile = pjoin(opt['output_dir'], 'param_card.inc')
 
2059
            ident_card = pjoin(self.me_dir,'Cards','ident_card.dat')
 
2060
            if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')):
 
2061
                default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')
 
2062
            elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')):
 
2063
                default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
 
2064
            elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')):
 
2065
                fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w')
 
2066
                fsock.write(' ')
 
2067
                fsock.close()
 
2068
                return
 
2069
            else:
 
2070
                subprocess.call(['python', 'write_param_card.py'], 
 
2071
                             cwd=pjoin(self.me_dir,'bin','internal','ufomodel'))
 
2072
                default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
 
2073
            param_card.write_inc_file(outfile, ident_card, default)
 
2074
         
 
2075
    ############################################################################      
 
2076
    def do_survey(self, line):
 
2077
        """Advanced commands: launch survey for the current process """
 
2078
        
 
2079
          
 
2080
        args = self.split_arg(line)
 
2081
        # Check argument's validity
 
2082
        self.check_survey(args)
 
2083
        # initialize / remove lhapdf mode
 
2084
 
 
2085
        if os.path.exists(pjoin(self.me_dir,'error')):
 
2086
            os.remove(pjoin(self.me_dir,'error'))
 
2087
                        
 
2088
        self.configure_directory()
 
2089
        # Save original random number
 
2090
        self.random_orig = self.random
 
2091
        logger.info("Using random number seed offset = %s" % self.random)
 
2092
        # Update random number
 
2093
        self.update_random()
 
2094
        self.save_random()
 
2095
        self.update_status('Running Survey', level=None)
 
2096
        if self.cluster_mode:
 
2097
            logger.info('Creating Jobs')
 
2098
 
 
2099
        logger.info('Working on SubProcesses')
 
2100
        self.total_jobs = 0
 
2101
        subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 
 
2102
                                                                 'subproc.mg'))]
 
2103
        
 
2104
        P_zero_result = [] # check the number of times where they are no phase-space
 
2105
        for nb_proc,subdir in enumerate(subproc):
 
2106
            subdir = subdir.strip()
 
2107
            Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
 
2108
            logger.info('    %s ' % subdir)
 
2109
            # clean previous run
 
2110
            for match in glob.glob(pjoin(Pdir, '*ajob*')):
 
2111
                if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
 
2112
                    os.remove(match)
 
2113
            for match in glob.glob(pjoin(Pdir, 'G*')):
 
2114
                if os.path.exists(pjoin(match,'results.dat')):
 
2115
                    os.remove(pjoin(match, 'results.dat'))
 
2116
            
 
2117
            #compile gensym
 
2118
            misc.compile(['gensym'], cwd=Pdir)
 
2119
            if not os.path.exists(pjoin(Pdir, 'gensym')):
 
2120
                raise MadEventError, 'Error make gensym not successful'
 
2121
 
 
2122
            # Launch gensym
 
2123
            p = misc.Popen(['./gensym'], stdin=subprocess.PIPE,
 
2124
                                 stdout=subprocess.PIPE, 
 
2125
                                 stderr=subprocess.STDOUT, cwd=Pdir)
 
2126
            sym_input = "%(points)d %(iterations)d %(accuracy)f \n" % self.opts
 
2127
            (stdout, stderr) = p.communicate(sym_input)
 
2128
            if os.path.exists(pjoin(self.me_dir,'error')):
 
2129
                files.mv(pjoin(self.me_dir,'error'), pjoin(Pdir,'ajob.no_ps.log'))
 
2130
                P_zero_result.append(subdir)
 
2131
                continue
 
2132
            
 
2133
            if not os.path.exists(pjoin(Pdir, 'ajob1')) or p.returncode:
 
2134
                logger.critical(stdout)
 
2135
                raise MadEventError, 'Error gensym run not successful'
 
2136
 
 
2137
 
 
2138
            misc.compile(['madevent'], cwd=Pdir)
 
2139
            
 
2140
            alljobs = glob.glob(pjoin(Pdir,'ajob*'))
 
2141
            self.total_jobs += len(alljobs)
 
2142
            for i, job in enumerate(alljobs):
 
2143
                job = os.path.basename(job)
 
2144
                self.launch_job('%s' % job, cwd=Pdir, remaining=(len(alljobs)-i-1), 
 
2145
                                                    run_type='survey on %s (%s/%s)' % (subdir,nb_proc+1,len(subproc)))
 
2146
                if os.path.exists(pjoin(self.me_dir,'error')):
 
2147
                    self.monitor(html=True)
 
2148
                    raise MadEventError, 'Error detected Stop running: %s' % \
 
2149
                                         open(pjoin(self.me_dir,'error')).read()
 
2150
                                         
 
2151
        # Check if all or only some fails
 
2152
        if P_zero_result:
 
2153
            if len(P_zero_result) == len(subproc):
 
2154
                raise ZeroResult, '%s' % \
 
2155
                    open(pjoin(Pdir,'ajob.no_ps.log')).read()
 
2156
            else:
 
2157
                logger.warning(''' %s SubProcesses doesn\'t have available phase-space.
 
2158
            Please check mass spectrum.''' % ','.join(P_zero_result))
 
2159
                
 
2160
        
 
2161
        self.monitor(run_type='All jobs submitted for survey', html=True)
 
2162
        cross, error = sum_html.make_all_html_results(self)
 
2163
        self.results.add_detail('cross', cross)
 
2164
        self.results.add_detail('error', error) 
 
2165
        self.update_status('End survey', 'parton', makehtml=False)
 
2166
 
 
2167
    ############################################################################      
 
2168
    def do_refine(self, line):
 
2169
        """Advanced commands: launch survey for the current process """
 
2170
        devnull = open(os.devnull, 'w')  
 
2171
        self.nb_refine += 1
 
2172
        args = self.split_arg(line)
 
2173
        # Check argument's validity
 
2174
        self.check_refine(args)
 
2175
        
 
2176
        precision = args[0]
 
2177
        if len(args) == 2:
 
2178
            max_process = args[1]
 
2179
        else:
 
2180
            max_process = 5
 
2181
 
 
2182
        # initialize / remove lhapdf mode
 
2183
        self.configure_directory()
 
2184
 
 
2185
        # Update random number
 
2186
        self.update_random()
 
2187
        self.save_random()
 
2188
 
 
2189
        if self.cluster_mode:
 
2190
            logger.info('Creating Jobs')
 
2191
        self.update_status('Refine results to %s' % precision, level=None)
 
2192
        
 
2193
        self.total_jobs = 0
 
2194
        subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 
 
2195
                                                                 'subproc.mg'))]
 
2196
        for nb_proc,subdir in enumerate(subproc):
 
2197
            subdir = subdir.strip()
 
2198
            Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
 
2199
            bindir = pjoin(os.path.relpath(self.dirbin, Pdir))
 
2200
                           
 
2201
            logger.info('    %s ' % subdir)
 
2202
            # clean previous run
 
2203
            for match in glob.glob(pjoin(Pdir, '*ajob*')):
 
2204
                if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
 
2205
                    os.remove(match)
 
2206
            
 
2207
            proc = misc.Popen([pjoin(bindir, 'gen_ximprove')],
 
2208
                                    stdout=devnull,
 
2209
                                    stdin=subprocess.PIPE,
 
2210
                                    cwd=Pdir)
 
2211
            proc.communicate('%s %s T\n' % (precision, max_process))
 
2212
 
 
2213
            if os.path.exists(pjoin(Pdir, 'ajob1')):
 
2214
                misc.compile(['madevent'], cwd=Pdir)
 
2215
                alljobs = glob.glob(pjoin(Pdir,'ajob*'))
 
2216
                
 
2217
                #remove associated results.dat (ensure to not mix with all data)
 
2218
                Gre = re.compile("\s*j=(G[\d\.\w]+)")
 
2219
                for job in alljobs:
 
2220
                    Gdirs = Gre.findall(open(job).read())
 
2221
                    for Gdir in Gdirs:
 
2222
                        if os.path.exists(pjoin(Pdir, Gdir, 'results.dat')):
 
2223
                            os.remove(pjoin(Pdir, Gdir,'results.dat'))
 
2224
                
 
2225
                nb_tot = len(alljobs)            
 
2226
                self.total_jobs += nb_tot
 
2227
                for i, job in enumerate(alljobs):
 
2228
                    job = os.path.basename(job)
 
2229
                    self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1), 
 
2230
                             run_type='Refine number %s on %s (%s/%s)' % 
 
2231
                             (self.nb_refine, subdir, nb_proc+1, len(subproc)))
 
2232
        self.monitor(run_type='All job submitted for refine number %s' % self.nb_refine, 
 
2233
                     html=True)
 
2234
        
 
2235
        self.update_status("Combining runs", level='parton')
 
2236
        try:
 
2237
            os.remove(pjoin(Pdir, 'combine_runs.log'))
 
2238
        except Exception:
 
2239
            pass
 
2240
        
 
2241
        bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses')))
 
2242
 
 
2243
        combine_runs.CombineRuns(self.me_dir)
 
2244
        
 
2245
        cross, error = sum_html.make_all_html_results(self)
 
2246
        self.results.add_detail('cross', cross)
 
2247
        self.results.add_detail('error', error)   
 
2248
 
 
2249
        self.update_status('finish refine', 'parton', makehtml=False)
 
2250
        devnull.close()
 
2251
        
 
2252
    ############################################################################ 
 
2253
    def do_combine_events(self, line):
 
2254
        """Advanced commands: Launch combine events"""
 
2255
 
 
2256
        args = self.split_arg(line)
 
2257
        # Check argument's validity
 
2258
        self.check_combine_events(args)
 
2259
 
 
2260
        self.update_status('Combining Events', level='parton')
 
2261
        try:
 
2262
            os.remove(pjoin(self.me_dir,'SubProcesses', 'combine.log'))
 
2263
        except Exception:
 
2264
            pass
 
2265
        self.cluster.launch_and_wait('../bin/internal/run_combine', 
 
2266
                                        cwd=pjoin(self.me_dir,'SubProcesses'),
 
2267
                                        stdout=pjoin(self.me_dir,'SubProcesses', 'combine.log'))
 
2268
        
 
2269
        output = misc.mult_try_open(pjoin(self.me_dir,'SubProcesses','combine.log')).read()
 
2270
        # Store the number of unweighted events for the results object
 
2271
        pat = re.compile(r'''\s*Unweighting\s*selected\s*(\d+)\s*events''')
 
2272
        try:      
 
2273
            nb_event = pat.search(output).groups()[0]
 
2274
        except AttributeError:
 
2275
            time.sleep(10)
 
2276
            try:
 
2277
                nb_event = pat.search(output).groups()[0]
 
2278
            except AttributeError:
 
2279
                logger.warning('Fail to read the number of unweighted events in the combine.log file')
 
2280
                nb_event = 0
 
2281
                
 
2282
        self.results.add_detail('nb_event', nb_event)
 
2283
        
 
2284
        
 
2285
        # Define The Banner
 
2286
        tag = self.run_card['run_tag']
 
2287
        # Update the banner with the pythia card
 
2288
        if not self.banner:
 
2289
            self.banner = banner_mod.recover_banner(self.results, 'parton')
 
2290
        self.banner.load_basic(self.me_dir)
 
2291
        # Add cross-section/event information
 
2292
        self.banner.add_generation_info(self.results.current['cross'], nb_event)
 
2293
        if not hasattr(self, 'random_orig'): self.random_orig = 0
 
2294
        self.banner.change_seed(self.random_orig)
 
2295
        if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)):
 
2296
            os.mkdir(pjoin(self.me_dir, 'Events', self.run_name))
 
2297
        self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, 
 
2298
                                     '%s_%s_banner.txt' % (self.run_name, tag)))
 
2299
        
 
2300
        misc.call(['%s/put_banner' % self.dirbin, 'events.lhe',
 
2301
                   str(self.random_orig)],
 
2302
                            cwd=pjoin(self.me_dir, 'Events'))
 
2303
        misc.call(['%s/put_banner'% self.dirbin, 'unweighted_events.lhe',
 
2304
                   str(self.random_orig)],
 
2305
                            cwd=pjoin(self.me_dir, 'Events'))
 
2306
        
 
2307
        eradir = self.options['exrootanalysis_path']
 
2308
        madir = self.options['madanalysis_path']
 
2309
        td = self.options['td_path']
 
2310
        if eradir and misc.is_executable(pjoin(eradir,'ExRootLHEFConverter'))  and\
 
2311
           os.path.exists(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe')):
 
2312
                if not os.path.exists(pjoin(self.me_dir, 'Events', self.run_name)):
 
2313
                    os.mkdir(pjoin(self.me_dir, 'Events', self.run_name))
 
2314
                self.create_root_file(output='%s/unweighted_events.root' % \
 
2315
                                                                  self.run_name)
 
2316
    
 
2317
    ############################################################################                                                                                                           
 
2318
    def do_compute_widths(self, line):
 
2319
        """Require MG5 directory: Compute automatically the widths of a set 
 
2320
        of particles"""
 
2321
 
 
2322
        warning_text = """Be carefull automatic computation of the width is 
 
2323
ONLY valid if all three (or more) body decay are negligeable. In doubt use a 
 
2324
calculator."""
 
2325
        
 
2326
        logger.warning(warning_text)
 
2327
        logger.info('In a future version of MG5 those mode will also be taken into account')
 
2328
      
 
2329
        args = self.split_arg(line)
 
2330
        # check the argument and return those in a dictionary format
 
2331
        args = self.check_compute_widths(args)
 
2332
        
 
2333
        if args['input']:
 
2334
            files.cp(args['input'], pjoin(self.me_dir, 'Cards'))
 
2335
        elif not args['force']: 
 
2336
            self.ask_edit_cards(['param_card.dat'], plot=False)
 
2337
        
 
2338
        model = args['model']
 
2339
        self.compute_widths(model, args)
 
2340
    
 
2341
    @staticmethod
 
2342
    def compute_widths(model, args):
 
2343
        
 
2344
        data = model.set_parameters_and_couplings(args['input'])
 
2345
        
 
2346
        # find UFO particles linked to the require names. 
 
2347
        decay_info = {}        
 
2348
        for pid in args['particles']:
 
2349
            particle = model.get_particle(pid)
 
2350
            decay_info[pid] = []
 
2351
            mass = abs(eval(str(particle.get('mass')), data).real)
 
2352
            data = model.set_parameters_and_couplings(args['input'], scale= mass)
 
2353
            for mode, expr in particle.partial_widths.items():
 
2354
                tmp_mass = mass    
 
2355
                for p in mode:
 
2356
                    tmp_mass -= abs(eval(str(p.mass), data))
 
2357
                if tmp_mass <=0:
 
2358
                    continue
 
2359
                
 
2360
                decay_to = [p.get('pdg_code') for p in mode]
 
2361
                value = eval(expr,{'cmath':cmath},data).real
 
2362
                if -1e-10 < value < 0:
 
2363
                    value = 0
 
2364
                if -1e-5 < value < 0:
 
2365
                    logger.warning('Partial width for %s > %s negative: %s automatically set to zero' %
 
2366
                                   (particle.get('name'), ' '.join([p.get('name') for p in mode]), value))
 
2367
                    value = 0
 
2368
                elif value < 0:
 
2369
                    raise Exception, 'Partial width for %s > %s negative: %s' % \
 
2370
                                   (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)
 
2371
                decay_info[particle.get('pdg_code')].append([decay_to, value])
 
2372
                          
 
2373
        MadEventCmd.update_width_in_param_card(decay_info, args['input'], args['output'])
 
2374
        
 
2375
    ############################################################################ 
 
2376
    def do_store_events(self, line):
 
2377
        """Advanced commands: Launch store events"""
 
2378
 
 
2379
        args = self.split_arg(line)
 
2380
        # Check argument's validity
 
2381
        self.check_combine_events(args)
 
2382
        self.update_status('Storing parton level results', level='parton')
 
2383
 
 
2384
        run = self.run_name
 
2385
        tag = self.run_card['run_tag']
 
2386
        devnull = open(os.devnull, 'w')
 
2387
 
 
2388
        if not os.path.exists(pjoin(self.me_dir, 'Events', run)):
 
2389
            os.mkdir(pjoin(self.me_dir, 'Events', run))
 
2390
        if not os.path.exists(pjoin(self.me_dir, 'HTML', run)):
 
2391
            os.mkdir(pjoin(self.me_dir, 'HTML', run))    
 
2392
        
 
2393
        # 1) Store overall process information
 
2394
        input = pjoin(self.me_dir, 'SubProcesses', 'results.dat')
 
2395
        output = pjoin(self.me_dir, 'SubProcesses', '%s_results.dat' % run)
 
2396
        files.cp(input, output) 
 
2397
 
 
2398
        # 2) Treat the files present in the P directory
 
2399
        for P_path in SubProcesses.get_subP(self.me_dir):
 
2400
            G_dir = [G for G in os.listdir(P_path) if G.startswith('G') and 
 
2401
                                                os.path.isdir(pjoin(P_path,G))]
 
2402
            for G in G_dir:
 
2403
                G_path = pjoin(P_path,G)
 
2404
                # Remove events file (if present)
 
2405
                if os.path.exists(pjoin(G_path, 'events.lhe')):
 
2406
                    os.remove(pjoin(G_path, 'events.lhe'))
 
2407
                # Store results.dat
 
2408
                if os.path.exists(pjoin(G_path, 'results.dat')):
 
2409
                    input = pjoin(G_path, 'results.dat')
 
2410
                    output = pjoin(G_path, '%s_results.dat' % run)
 
2411
                    files.cp(input, output) 
 
2412
                # Store log
 
2413
                if os.path.exists(pjoin(G_path, 'log.txt')):
 
2414
                    input = pjoin(G_path, 'log.txt')
 
2415
                    output = pjoin(G_path, '%s_log.txt' % run)
 
2416
                    files.mv(input, output) 
 
2417
                # Grid
 
2418
                for name in ['ftn26']:
 
2419
                    if os.path.exists(pjoin(G_path, name)):
 
2420
                        if os.path.exists(pjoin(G_path, '%s_%s.gz'%(run,name))):
 
2421
                            os.remove(pjoin(G_path, '%s_%s.gz'%(run,name)))
 
2422
                        input = pjoin(G_path, name)
 
2423
                        output = pjoin(G_path, '%s_%s' % (run,name))
 
2424
                        files.mv(input, output) 
 
2425
                        misc.call(['gzip', output], stdout=devnull, 
 
2426
                                        stderr=devnull, cwd=G_path)
 
2427
                # Delete ftn25 to ensure reproducible runs
 
2428
                if os.path.exists(pjoin(G_path, 'ftn25')):
 
2429
                    os.remove(pjoin(G_path, 'ftn25'))
 
2430
 
 
2431
        # 3) Update the index.html
 
2432
        gen_crossxhtml.GenCardHTML(self.results)
 
2433
        
 
2434
        # 4) Move the Files present in Events directory
 
2435
        E_path = pjoin(self.me_dir, 'Events')
 
2436
        O_path = pjoin(self.me_dir, 'Events', run)
 
2437
        # The events file
 
2438
        for name in ['events.lhe', 'unweighted_events.lhe']:
 
2439
            if os.path.exists(pjoin(E_path, name)):
 
2440
                if os.path.exists(pjoin(O_path, '%s.gz' % name)):
 
2441
                    os.remove(pjoin(O_path, '%s.gz' % name))
 
2442
                input = pjoin(E_path, name)
 
2443
                output = pjoin(O_path, name)
 
2444
                files.mv(input, output) 
 
2445
                misc.call(['gzip', output], stdout=devnull, stderr=devnull, 
 
2446
                                                                     cwd=O_path) 
 
2447
        self.update_status('End Parton', level='parton', makehtml=False)
 
2448
        devnull.close()
 
2449
 
 
2450
    ############################################################################ 
 
2451
    def do_create_gridpack(self, line):
 
2452
        """Advanced commands: Create gridpack from present run"""
 
2453
 
 
2454
        self.update_status('Creating gridpack', level='parton')
 
2455
        args = self.split_arg(line)
 
2456
        self.check_combine_events(args)
 
2457
        if not self.run_tag: self.run_tag = 'tag_1'
 
2458
        os.system("sed -i.bak \"s/ *.false.*=.*GridRun/  .true.  =  GridRun/g\" %s/Cards/grid_card.dat" \
 
2459
                  % self.me_dir)
 
2460
        misc.call(['./bin/internal/restore_data', self.run_name],
 
2461
                        cwd=self.me_dir)
 
2462
        misc.call(['./bin/internal/store4grid',
 
2463
                         self.run_name, self.run_tag],
 
2464
                        cwd=self.me_dir)
 
2465
        misc.call(['./bin/internal/clean'], cwd=self.me_dir)
 
2466
        misc.call(['./bin/internal/make_gridpack'], cwd=self.me_dir)
 
2467
        files.mv(pjoin(self.me_dir, 'gridpack.tar.gz'), 
 
2468
                pjoin(self.me_dir, '%s_gridpack.tar.gz' % self.run_name))
 
2469
        os.system("sed -i.bak \"s/\s*.true.*=.*GridRun/  .false.  =  GridRun/g\" %s/Cards/grid_card.dat" \
 
2470
                  % self.me_dir)
 
2471
        self.update_status('gridpack created', level='gridpack')
 
2472
        
 
2473
    ############################################################################      
 
2474
    def do_pythia(self, line):
 
2475
        """launch pythia"""
 
2476
        
 
2477
        # Check argument's validity
 
2478
        args = self.split_arg(line)
 
2479
        if '--no_default' in args:
 
2480
            if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia_card.dat')):
 
2481
                return
 
2482
            no_default = True
 
2483
            args.remove('--no_default')
 
2484
        else:
 
2485
            no_default = False
 
2486
                                    
 
2487
        self.check_pythia(args)        
 
2488
        # the args are modify and the last arg is always the mode 
 
2489
        if not no_default:
 
2490
            self.ask_pythia_run_configuration(args[-1])
 
2491
 
 
2492
        # Update the banner with the pythia card
 
2493
        if not self.banner:
 
2494
            self.banner = banner_mod.recover_banner(self.results, 'pythia')
 
2495
                     
 
2496
        # initialize / remove lhapdf mode        
 
2497
        self.configure_directory()
 
2498
 
 
2499
        pythia_src = pjoin(self.options['pythia-pgs_path'],'src')
 
2500
        
 
2501
        self.update_status('Running Pythia', 'pythia')
 
2502
        try:
 
2503
            os.remove(pjoin(self.me_dir,'Events','pythia.done'))
 
2504
        except Exception:
 
2505
            pass
 
2506
        
 
2507
        ## LAUNCHING PYTHIA
 
2508
        tag = self.run_tag
 
2509
        pythia_log = pjoin(self.me_dir, 'Events', self.run_name , '%s_pythia.log' % tag)
 
2510
        self.cluster.launch_and_wait('../bin/internal/run_pythia', 
 
2511
                        argument= [pythia_src], stdout= pythia_log,
 
2512
                        stderr=subprocess.STDOUT,
 
2513
                        cwd=pjoin(self.me_dir,'Events'))
 
2514
 
 
2515
        if not os.path.exists(pjoin(self.me_dir,'Events','pythia.done')):
 
2516
            logger.warning('Fail to produce pythia output. More info in \n     %s' % pythia_log)
 
2517
            return
 
2518
        else:
 
2519
            os.remove(pjoin(self.me_dir,'Events','pythia.done'))
 
2520
        
 
2521
        self.to_store.append('pythia')
 
2522
        
 
2523
        # Find the matched cross-section
 
2524
        if int(self.run_card['ickkw']):
 
2525
            # read the line from the bottom of the file
 
2526
            pythia_log = misc.BackRead(pjoin(self.me_dir,'Events', self.run_name, 
 
2527
                                                         '%s_pythia.log' % tag))
 
2528
            pythiare = re.compile("\s*I\s+0 All included subprocesses\s+I\s+(?P<generated>\d+)\s+(?P<tried>\d+)\s+I\s+(?P<xsec>[\d\.D\-+]+)\s+I")            
 
2529
            for line in pythia_log:
 
2530
                info = pythiare.search(line)
 
2531
                if not info:
 
2532
                    continue
 
2533
                try:
 
2534
                    # Pythia cross section in mb, we want pb
 
2535
                    sigma_m = float(info.group('xsec').replace('D','E')) *1e9
 
2536
                    Nacc = int(info.group('generated'))
 
2537
                    Ntry = int(info.group('tried'))
 
2538
                except ValueError:
 
2539
                    # xsec is not float - this should not happen
 
2540
                    self.results.add_detail('cross_pythia', 0)
 
2541
                    self.results.add_detail('nb_event_pythia', 0)
 
2542
                    self.results.add_detail('error_pythia', 0)
 
2543
                else:
 
2544
                    self.results.add_detail('cross_pythia', sigma_m)
 
2545
                    self.results.add_detail('nb_event_pythia', Nacc)
 
2546
                    #compute pythia error
 
2547
                    error = self.results[self.run_name].return_tag(self.run_tag)['error']                    
 
2548
                    error_m = math.sqrt((error * Nacc/Ntry)**2 + sigma_m**2 *(1-Nacc/Ntry)/Nacc)
 
2549
                    # works both for fixed number of generated events and fixed accepted events
 
2550
                    self.results.add_detail('error_pythia', error_m)
 
2551
                break                 
 
2552
 
 
2553
            pythia_log.close()
 
2554
        
 
2555
        pydir = pjoin(self.options['pythia-pgs_path'], 'src')
 
2556
        eradir = self.options['exrootanalysis_path']
 
2557
        madir = self.options['madanalysis_path']
 
2558
        td = self.options['td_path']
 
2559
        
 
2560
        
 
2561
        self.banner.add(pjoin(self.me_dir, 'Cards','pythia_card.dat'))
 
2562
        banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag))
 
2563
        self.banner.write(banner_path)
 
2564
        
 
2565
        # Creating LHE file
 
2566
        self.run_hep2lhe(banner_path)
 
2567
        if int(self.run_card['ickkw']):
 
2568
            misc.call(['gzip','-f','beforeveto.tree'], 
 
2569
                                                cwd=pjoin(self.me_dir,'Events'))
 
2570
            files.mv(pjoin(self.me_dir,'Events','beforeveto.tree.gz'), 
 
2571
                     pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_beforeveto.tree.gz'))
 
2572
 
 
2573
        # Plot for pythia
 
2574
        self.create_plot('Pythia')
 
2575
 
 
2576
        if os.path.exists(pjoin(self.me_dir,'Events','pythia_events.lhe')):
 
2577
            shutil.move(pjoin(self.me_dir,'Events','pythia_events.lhe'),
 
2578
            pjoin(self.me_dir,'Events', self.run_name,'%s_pythia_events.lhe' % tag))
 
2579
            os.system('gzip -f %s' % pjoin(self.me_dir,'Events', self.run_name,
 
2580
                                        '%s_pythia_events.lhe' % tag))      
 
2581
 
 
2582
        
 
2583
        self.update_status('finish', level='pythia', makehtml=False)
 
2584
        self.exec_cmd('pgs --no_default', postcmd=False, printcmd=False)
 
2585
        if self.options['delphes_path']:
 
2586
            self.exec_cmd('delphes --no_default', postcmd=False, printcmd=False)
 
2587
        self.print_results_in_shell(self.results.current)
 
2588
    
 
2589
    def get_available_tag(self):
 
2590
        """create automatically a tag"""
 
2591
        
 
2592
        used_tags = [r['tag'] for r in self.results[self.run_name]]
 
2593
        i=0
 
2594
        while 1:
 
2595
            i+=1
 
2596
            if 'tag_%s' %i not in used_tags:
 
2597
                return 'tag_%s' % i
 
2598
   
 
2599
    
 
2600
    
 
2601
    ################################################################################
 
2602
    def do_remove(self, line):
 
2603
        """Remove one/all run or only part of it"""
 
2604
 
 
2605
        args = self.split_arg(line)
 
2606
        run, tag, mode = self.check_remove(args)
 
2607
        if 'banner' in mode:
 
2608
            mode.append('all')
 
2609
        
 
2610
        
 
2611
        if run == 'all':
 
2612
            # Check first if they are not a run with a name run.
 
2613
            if os.path.exists(pjoin(self.me_dir, 'Events', 'all')):
 
2614
                logger.warning('A run with name all exists. So we will not supress all processes.')
 
2615
            else:
 
2616
                for match in glob.glob(pjoin(self.me_dir, 'Events','*','*_banner.txt')):
 
2617
                    run = match.rsplit(os.path.sep,2)[1]
 
2618
                    try:
 
2619
                        self.exec_cmd('remove %s %s' % (run, ' '.join(args[1:]) ) )
 
2620
                    except self.InvalidCmd, error:
 
2621
                        logger.info(error)
 
2622
                        pass # run already clear
 
2623
                return
 
2624
            
 
2625
        # Check that run exists
 
2626
        if not os.path.exists(pjoin(self.me_dir, 'Events', run)):
 
2627
            raise self.InvalidCmd('No run \'%s\' detected' % run)
 
2628
 
 
2629
        try:
 
2630
            self.resuls.def_current(run)
 
2631
            self.update_status(' Cleaning %s' % run, level=None)
 
2632
        except Exception:
 
2633
            misc.sprint('fail to update results or html status')
 
2634
            pass # Just ensure that html never makes crash this function
 
2635
 
 
2636
 
 
2637
        # Found the file to delete
 
2638
        
 
2639
        to_delete = glob.glob(pjoin(self.me_dir, 'Events', run, '*'))
 
2640
        to_delete += glob.glob(pjoin(self.me_dir, 'HTML', run, '*'))
 
2641
        # forbid the banner to be removed
 
2642
        to_delete = [os.path.basename(f) for f in to_delete if 'banner' not in f]
 
2643
        if tag:
 
2644
            to_delete = [f for f in to_delete if tag in f]
 
2645
            if 'parton' in mode or 'all' in mode:
 
2646
                try:
 
2647
                    if self.results[run][0]['tag'] != tag:
 
2648
                        raise Exception, 'dummy'
 
2649
                except Exception:
 
2650
                    pass
 
2651
                else:
 
2652
                    nb_rm = len(to_delete)
 
2653
                    if os.path.exists(pjoin(self.me_dir, 'Events', run, 'events.lhe.gz')):
 
2654
                        to_delete.append('events.lhe.gz')
 
2655
                    if os.path.exists(pjoin(self.me_dir, 'Events', run, 'unweighted_events.lhe.gz')):
 
2656
                        to_delete.append('unweighted_events.lhe.gz')
 
2657
                    if os.path.exists(pjoin(self.me_dir, 'HTML', run,'plots_parton.html')):
 
2658
                        to_delete.append(pjoin(self.me_dir, 'HTML', run,'plots_parton.html'))                       
 
2659
                    if nb_rm != len(to_delete):
 
2660
                        logger.warning('Be carefull that partonic information are on the point to be removed.')
 
2661
        if 'all' in mode:
 
2662
            pass # delete everything
 
2663
        else:
 
2664
            if 'pythia' not in mode:
 
2665
                to_delete = [f for f in to_delete if 'pythia' not in f]
 
2666
            if 'pgs' not in mode:
 
2667
                to_delete = [f for f in to_delete if 'pgs' not in f]
 
2668
            if 'delphes' not in mode:
 
2669
                to_delete = [f for f in to_delete if 'delphes' not in f]
 
2670
            if 'parton' not in mode:
 
2671
                to_delete = [f for f in to_delete if 'delphes' in f 
 
2672
                                                      or 'pgs' in f 
 
2673
                                                      or 'pythia' in f]
 
2674
        if not self.force and len(to_delete):
 
2675
            question = 'Do you want to delete the following files?\n     %s' % \
 
2676
                               '\n    '.join(to_delete)
 
2677
            ans = self.ask(question, 'y', choices=['y','n'])
 
2678
        else:
 
2679
            ans = 'y'
 
2680
        
 
2681
        if ans == 'y':
 
2682
            for file2rm in to_delete:
 
2683
                if os.path.exists(pjoin(self.me_dir, 'Events', run, file2rm)):
 
2684
                    try:
 
2685
                        os.remove(pjoin(self.me_dir, 'Events', run, file2rm))
 
2686
                    except Exception:
 
2687
                        shutil.rmtree(pjoin(self.me_dir, 'Events', run, file2rm))
 
2688
                else:
 
2689
                    try:
 
2690
                        os.remove(pjoin(self.me_dir, 'HTML', run, file2rm))
 
2691
                    except Exception:
 
2692
                        shutil.rmtree(pjoin(self.me_dir, 'HTML', run, file2rm))
 
2693
 
 
2694
 
 
2695
 
 
2696
        # Remove file in SubProcess directory
 
2697
        if 'all' in mode or 'channel' in mode:
 
2698
            try:
 
2699
                if tag and self.results[run][0]['tag'] != tag:
 
2700
                    raise Exception, 'dummy'
 
2701
            except Exception:
 
2702
                pass
 
2703
            else:
 
2704
                to_delete = glob.glob(pjoin(self.me_dir, 'SubProcesses', '%s*' % run))
 
2705
                to_delete += glob.glob(pjoin(self.me_dir, 'SubProcesses', '*','%s*' % run))
 
2706
                to_delete += glob.glob(pjoin(self.me_dir, 'SubProcesses', '*','*','%s*' % run))
 
2707
 
 
2708
                if self.force or len(to_delete) == 0:
 
2709
                    ans = 'y'
 
2710
                else:
 
2711
                    question = 'Do you want to delete the following files?\n     %s' % \
 
2712
                               '\n    '.join(to_delete)
 
2713
                    ans = self.ask(question, 'y', choices=['y','n'])
 
2714
 
 
2715
                if ans == 'y':
 
2716
                    for file2rm in to_delete:
 
2717
                        os.remove(file2rm)
 
2718
                        
 
2719
        if 'banner' in mode:
 
2720
            to_delete = glob.glob(pjoin(self.me_dir, 'Events', run, '*'))
 
2721
            if tag:
 
2722
                # remove banner
 
2723
                try:
 
2724
                    os.remove(pjoin(self.me_dir, 'Events',run,'%s_%s_banner.txt' % (run,tag)))
 
2725
                except Exception:
 
2726
                    logger.warning('fail to remove the banner')
 
2727
                # remove the run from the html output
 
2728
                if run in self.results:
 
2729
                    self.results.delete_run(run, tag)
 
2730
                    return
 
2731
            elif any(['banner' not in os.path.basename(p) for p in to_delete]):
 
2732
                if to_delete:
 
2733
                    raise MadGraph5Error, '''Some output still exists for this run. 
 
2734
                Please remove those output first. Do for example: 
 
2735
                remove %s all banner
 
2736
                ''' % run
 
2737
            else:
 
2738
                shutil.rmtree(pjoin(self.me_dir, 'Events',run))
 
2739
                if run in self.results:
 
2740
                    self.results.delete_run(run)
 
2741
                    return
 
2742
        else:
 
2743
            logger.info('''The banner is not removed. In order to remove it run:
 
2744
    remove %s all banner %s''' % (run, tag and '--tag=%s ' % tag or '')) 
 
2745
 
 
2746
        # update database.
 
2747
        self.results.clean(mode, run, tag)
 
2748
        self.update_status('', level='all')
 
2749
 
 
2750
 
 
2751
 
 
2752
    ################################################################################
 
2753
    def do_plot(self, line):
 
2754
        """Create the plot for a given run"""
 
2755
 
 
2756
        # Since in principle, all plot are already done automaticaly
 
2757
        self.store_result()
 
2758
        args = self.split_arg(line)
 
2759
        # Check argument's validity
 
2760
        self.check_plot(args)
 
2761
        logger.info('plot for run %s' % self.run_name)
 
2762
        
 
2763
        self.ask_edit_cards([], args, plot=True)
 
2764
                
 
2765
        if any([arg in ['all','parton'] for arg in args]):
 
2766
            filename = pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe')
 
2767
            if os.path.exists(filename+'.gz'):
 
2768
                os.system('gunzip -f %s' % (filename+'.gz') )
 
2769
            if  os.path.exists(filename):
 
2770
                shutil.move(filename, pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'))
 
2771
                self.create_plot('parton')
 
2772
                shutil.move(pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'), filename)
 
2773
                os.system('gzip -f %s' % filename)
 
2774
            else:
 
2775
                logger.info('No valid files for partonic plot') 
 
2776
                
 
2777
        if any([arg in ['all','pythia'] for arg in args]):
 
2778
            filename = pjoin(self.me_dir, 'Events' ,self.run_name,
 
2779
                                          '%s_pythia_events.lhe' % self.run_tag)
 
2780
            if os.path.exists(filename+'.gz'):
 
2781
                os.system('gunzip -f %s' % (filename+'.gz') )
 
2782
            if  os.path.exists(filename):
 
2783
                shutil.move(filename, pjoin(self.me_dir, 'Events','pythia_events.lhe'))
 
2784
                self.create_plot('Pythia')
 
2785
                shutil.move(pjoin(self.me_dir, 'Events','pythia_events.lhe'), filename)
 
2786
                os.system('gzip -f %s' % filename)                
 
2787
            else:
 
2788
                logger.info('No valid files for pythia plot')
 
2789
                
 
2790
                    
 
2791
        if any([arg in ['all','pgs'] for arg in args]):
 
2792
            filename = pjoin(self.me_dir, 'Events', self.run_name, 
 
2793
                                            '%s_pgs_events.lhco' % self.run_tag)
 
2794
            if os.path.exists(filename+'.gz'):
 
2795
                os.system('gunzip -f %s' % (filename+'.gz') )
 
2796
            if  os.path.exists(filename):
 
2797
                self.create_plot('PGS')
 
2798
                os.system('gzip -f %s' % filename)                
 
2799
            else:
 
2800
                logger.info('No valid files for pgs plot')
 
2801
                
 
2802
        if any([arg in ['all','delphes'] for arg in args]):
 
2803
            filename = pjoin(self.me_dir, 'Events', self.run_name, 
 
2804
                                        '%s_delphes_events.lhco' % self.run_tag)
 
2805
            if os.path.exists(filename+'.gz'):
 
2806
                os.system('gunzip -f %s' % (filename+'.gz') )
 
2807
            if  os.path.exists(filename):
 
2808
                #shutil.move(filename, pjoin(self.me_dir, 'Events','delphes_events.lhco'))
 
2809
                self.create_plot('Delphes')
 
2810
                #shutil.move(pjoin(self.me_dir, 'Events','delphes_events.lhco'), filename)
 
2811
                os.system('gzip -f %s' % filename)                
 
2812
            else:
 
2813
                logger.info('No valid files for delphes plot')
 
2814
 
 
2815
                
 
2816
    
 
2817
    def store_result(self):
 
2818
        """ tar the pythia results. This is done when we are quite sure that 
 
2819
        the pythia output will not be use anymore """
 
2820
 
 
2821
 
 
2822
        if not self.run_name:
 
2823
            return
 
2824
        
 
2825
        self.results.save()
 
2826
        
 
2827
        if not self.to_store:
 
2828
            return 
 
2829
        
 
2830
        tag = self.run_card['run_tag']
 
2831
        if 'pythia' in self.to_store:
 
2832
            self.update_status('Storing Pythia files of Previous run', level='pythia', error=True)
 
2833
            os.system('mv -f %(path)s/pythia_events.hep %(path)s/%(name)s/%(tag)s_pythia_events.hep' % 
 
2834
                  {'name': self.run_name, 'path' : pjoin(self.me_dir,'Events'),
 
2835
                   'tag':tag})
 
2836
            os.system('gzip -f %s/%s_pythia_events.hep' % ( 
 
2837
                                pjoin(self.me_dir,'Events',self.run_name), tag))
 
2838
            self.to_store.remove('pythia')
 
2839
            self.update_status('Done', level='pythia',makehtml=False,error=True)
 
2840
        
 
2841
        self.to_store = []
 
2842
            
 
2843
    def launch_job(self,exe, cwd=None, stdout=None, argument = [], remaining=0, 
 
2844
                    run_type='', mode=None, **opt):
 
2845
        """ """
 
2846
        argument = [str(arg) for arg in argument]
 
2847
        if mode is None:
 
2848
            mode = self.cluster_mode
 
2849
        
 
2850
        # ensure that exe is executable
 
2851
        if os.path.exists(exe) and not os.access(exe, os.X_OK):
 
2852
            os.system('chmod +x %s ' % exe)
 
2853
 
 
2854
        elif (cwd and os.path.exists(pjoin(cwd, exe))) and not \
 
2855
                                            os.access(pjoin(cwd, exe), os.X_OK):
 
2856
            os.system('chmod +x %s ' % pjoin(cwd, exe))
 
2857
                    
 
2858
        if mode == 0:
 
2859
            self.update_status((remaining, 1, 
 
2860
                                self.total_jobs - remaining -1, run_type), level=None, force=False)
 
2861
            start = time.time()
 
2862
            #os.system('cd %s; ./%s' % (cwd,exe))
 
2863
            status = misc.call(['./'+exe] + argument, cwd=cwd, 
 
2864
                                                           stdout=stdout, **opt)
 
2865
            logger.info('%s run in %f s' % (exe, time.time() -start))
 
2866
            if status:
 
2867
                raise MadGraph5Error, '%s didn\'t stop properly. Stop all computation' % exe
 
2868
 
 
2869
 
 
2870
        elif mode == 1:
 
2871
            # For condor cluster, create the input/output files
 
2872
            if 'ajob' in exe: 
 
2873
                input_files = ['madevent','input_app.txt','symfact.dat','iproc.dat',
 
2874
                               pjoin(self.me_dir, 'SubProcesses','randinit')]
 
2875
                output_files = []
 
2876
 
 
2877
                #Find the correct PDF input file
 
2878
                input_files.append(self.get_pdf_input_filename())
 
2879
                        
 
2880
                #Find the correct ajob
 
2881
                Gre = re.compile("\s*j=(G[\d\.\w]+)")
 
2882
                Ire = re
 
2883
                try : 
 
2884
                    fsock = open(exe)
 
2885
                except Exception:
 
2886
                    fsock = open(pjoin(cwd,exe))
 
2887
                text = fsock.read()
 
2888
                output_files = Gre.findall(text)
 
2889
                if not output_files:
 
2890
                    Ire = re.compile("for i in ([\d\.\s]*) ; do")
 
2891
                    data = Ire.findall(text)
 
2892
                    data = ' '.join(data).split()
 
2893
                    for nb in data:
 
2894
                        output_files.append('G%s' % nb)
 
2895
                else:
 
2896
                    for G in output_files:
 
2897
                        if os.path.isdir(pjoin(cwd,G)):
 
2898
                            input_files.append(G)
 
2899
                
 
2900
                #submitting
 
2901
                self.cluster.submit2(exe, stdout=stdout, cwd=cwd, 
 
2902
                             input_files=input_files, output_files=output_files)
 
2903
            
 
2904
            else:
 
2905
                self.cluster.submit(exe, stdout=stdout, cwd=cwd)
 
2906
 
 
2907
        elif mode == 2:
 
2908
            self.cluster.submit(exe, stdout=stdout, cwd=cwd)
 
2909
            
 
2910
            
 
2911
    ############################################################################
 
2912
    def find_madevent_mode(self):
 
2913
        """Find if Madevent is in Group mode or not"""
 
2914
        
 
2915
        # The strategy is too look in the files Source/run_configs.inc
 
2916
        # if we found: ChanPerJob=3 then it's a group mode.
 
2917
        file_path = pjoin(self.me_dir, 'Source', 'run_config.inc')
 
2918
        text = open(file_path).read()
 
2919
        if re.search(r'''s*parameter\s+\(ChanPerJob=2\)''', text, re.I+re.M):
 
2920
            return 'group'
 
2921
        else:
 
2922
            return 'v4'
 
2923
    
 
2924
    ############################################################################
 
2925
    def monitor(self, run_type='monitor', mode=None, html=False):
 
2926
        """ monitor the progress of running job """
 
2927
        
 
2928
        starttime = time.time()
 
2929
        if mode is None:
 
2930
            mode = self.cluster_mode
 
2931
        if mode > 0:
 
2932
            if html:
 
2933
                update_status = lambda idle, run, finish: \
 
2934
                    self.update_status((idle, run, finish, run_type), level=None,
 
2935
                                       force=False, starttime=starttime)
 
2936
            else:
 
2937
                update_status = lambda idle, run, finish: None
 
2938
            try:    
 
2939
                self.cluster.wait(self.me_dir, update_status)            
 
2940
            except Exception, error:
 
2941
                logger.info(error)
 
2942
                if not self.force:
 
2943
                    ans = self.ask('Cluster Error detected. Do you want to clean the queue?',
 
2944
                             default = 'y', choices=['y','n'])
 
2945
                else:
 
2946
                    ans = 'y'
 
2947
                if ans:
 
2948
                    self.cluster.remove()
 
2949
                raise
 
2950
            except KeyboardInterrupt, error:
 
2951
                self.cluster.remove()
 
2952
                raise                            
 
2953
        
 
2954
        
 
2955
 
 
2956
    ############################################################################   
 
2957
    def configure_directory(self):
 
2958
        """ All action require before any type of run """   
 
2959
 
 
2960
 
 
2961
        # Basic check
 
2962
        assert os.path.exists(pjoin(self.me_dir,'SubProcesses'))
 
2963
        
 
2964
        #see when the last file was modified
 
2965
        time_mod = max([os.path.getctime(pjoin(self.me_dir,'Cards','run_card.dat')),
 
2966
                        os.path.getctime(pjoin(self.me_dir,'Cards','param_card.dat'))])
 
2967
        
 
2968
        if self.configured > time_mod and hasattr(self, 'random'):
 
2969
            return
 
2970
        else:
 
2971
            self.configured = time.time()
 
2972
        self.update_status('compile directory', level=None, update_results=True)
 
2973
        if self.options['automatic_html_opening']:
 
2974
            misc.open_file(os.path.join(self.me_dir, 'crossx.html'))
 
2975
            self.options['automatic_html_opening'] = False
 
2976
            #open only once the web page
 
2977
        # Change current working directory
 
2978
        self.launching_dir = os.getcwd()
 
2979
        
 
2980
        # Check if we need the MSSM special treatment
 
2981
        model = self.find_model_name()
 
2982
        if model == 'mssm' or model.startswith('mssm-'):
 
2983
            param_card = pjoin(self.me_dir, 'Cards','param_card.dat')
 
2984
            mg5_param = pjoin(self.me_dir, 'Source', 'MODEL', 'MG5_param.dat')
 
2985
            check_param_card.convert_to_mg5card(param_card, mg5_param)
 
2986
            check_param_card.check_valid_param_card(mg5_param)
 
2987
        
 
2988
        # limit the number of event to 100k
 
2989
        self.check_nb_events()
 
2990
 
 
2991
        # set environment variable for lhapdf.
 
2992
        if self.run_card['pdlabel'] == "lhapdf":
 
2993
            os.environ['lhapdf'] = 'True'
 
2994
        elif 'lhapdf' in os.environ.keys():
 
2995
            del os.environ['lhapdf']
 
2996
        self.pdffile = None
 
2997
            
 
2998
        # set random number
 
2999
        if self.run_card['iseed'] != '0':
 
3000
            self.random = int(self.run_card['iseed'])
 
3001
            self.run_card['iseed'] = '0'
 
3002
            # Reset seed in run_card to 0, to ensure that following runs
 
3003
            # will be statistically independent
 
3004
            text = open(pjoin(self.me_dir, 'Cards','run_card.dat')).read()
 
3005
            (t,n) = re.subn(r'\d+\s*= iseed','0 = iseed',text)
 
3006
            open(pjoin(self.me_dir, 'Cards','run_card.dat'),'w').write(t)
 
3007
        elif os.path.exists(pjoin(self.me_dir,'SubProcesses','randinit')):
 
3008
            for line in open(pjoin(self.me_dir,'SubProcesses','randinit')):
 
3009
                data = line.split('=')
 
3010
                assert len(data) ==2
 
3011
                self.random = int(data[1])
 
3012
                break
 
3013
        else:
 
3014
            self.random = random.randint(1, 30107)
 
3015
                                                               
 
3016
        if self.run_card['ickkw'] == '2':
 
3017
            logger.info('Running with CKKW matching')
 
3018
            self.treat_CKKW_matching()
 
3019
            
 
3020
        # create param_card.inc and run_card.inc
 
3021
        self.do_treatcards('')
 
3022
        
 
3023
        # Compile
 
3024
        for name in ['../bin/internal/gen_ximprove', 'all', 
 
3025
                     '../bin/internal/combine_events']:
 
3026
            misc.compile(arg=[name], cwd=os.path.join(self.me_dir, 'Source'))
 
3027
        
 
3028
        
 
3029
    ############################################################################
 
3030
    ##  HELPING ROUTINE
 
3031
    ############################################################################
 
3032
    @staticmethod
 
3033
    def check_dir(path, default=''):
 
3034
        """check if the directory exists. if so return the path otherwise the 
 
3035
        default"""
 
3036
         
 
3037
        if os.path.isdir(path):
 
3038
            return path
 
3039
        else:
 
3040
            return default
 
3041
        
 
3042
    ############################################################################
 
3043
    def set_run_name(self, name, tag=None, level='parton', reload_card=False):
 
3044
        """define the run name, the run_tag, the banner and the results."""
 
3045
        
 
3046
        # when are we force to change the tag new_run:previous run requiring changes
 
3047
        upgrade_tag = {'parton': ['parton','pythia','pgs','delphes'],
 
3048
                       'pythia': ['pythia','pgs','delphes'],
 
3049
                       'pgs': ['pgs'],
 
3050
                       'delphes':['delphes'],
 
3051
                       'plot':[]}
 
3052
        
 
3053
        
 
3054
 
 
3055
        if name == self.run_name:        
 
3056
            if reload_card:
 
3057
                run_card = pjoin(self.me_dir, 'Cards','run_card.dat')
 
3058
                self.run_card = banner_mod.RunCard(run_card)
 
3059
 
 
3060
            #check if we need to change the tag
 
3061
            if tag:
 
3062
                self.run_card['run_tag'] = tag
 
3063
                self.run_tag = tag
 
3064
                self.results.add_run(self.run_name, self.run_card)
 
3065
            else:
 
3066
                for tag in upgrade_tag[level]:
 
3067
                    if getattr(self.results[self.run_name][-1], tag):
 
3068
                        tag = self.get_available_tag()
 
3069
                        self.run_card['run_tag'] = tag
 
3070
                        self.run_tag = tag
 
3071
                        self.results.add_run(self.run_name, self.run_card)                        
 
3072
                        break
 
3073
            return # Nothing to do anymore
 
3074
        
 
3075
        # save/clean previous run
 
3076
        if self.run_name:
 
3077
            self.store_result()
 
3078
        # store new name
 
3079
        self.run_name = name
 
3080
        
 
3081
        # Read run_card
 
3082
        run_card = pjoin(self.me_dir, 'Cards','run_card.dat')
 
3083
        self.run_card = banner_mod.RunCard(run_card)
 
3084
 
 
3085
        new_tag = False
 
3086
        # First call for this run -> set the banner
 
3087
        self.banner = banner_mod.recover_banner(self.results, level)
 
3088
        if tag:
 
3089
            self.run_card['run_tag'] = tag
 
3090
            new_tag = True
 
3091
        elif not self.run_name in self.results and level =='parton':
 
3092
            pass # No results yet, so current tag is fine
 
3093
        elif not self.run_name in self.results:
 
3094
            #This is only for case when you want to trick the interface
 
3095
            logger.warning('Trying to run data on unknown run.')
 
3096
            self.results.add_run(name, self.run_card)
 
3097
            self.results.update('add run %s' % name, 'all', makehtml=False)
 
3098
        else:
 
3099
            for tag in upgrade_tag[level]:
 
3100
                
 
3101
                if getattr(self.results[self.run_name][-1], tag):
 
3102
                    # LEVEL is already define in the last tag -> need to switch tag
 
3103
                    tag = self.get_available_tag()
 
3104
                    self.run_card['run_tag'] = tag
 
3105
                    new_tag = True
 
3106
                    break
 
3107
            if not new_tag:
 
3108
                # We can add the results to the current run
 
3109
                tag = self.results[self.run_name][-1]['tag']
 
3110
                self.run_card['run_tag'] = tag # ensure that run_tag is correct                
 
3111
             
 
3112
                    
 
3113
        if name in self.results and not new_tag:
 
3114
            self.results.def_current(self.run_name)
 
3115
        else:
 
3116
            self.results.add_run(self.run_name, self.run_card)
 
3117
 
 
3118
        self.run_tag = self.run_card['run_tag']
 
3119
 
 
3120
        # Return the tag of the previous run having the required data for this
 
3121
        # tag/run to working wel.
 
3122
        if level == 'parton':
 
3123
            return
 
3124
        elif level == 'pythia':
 
3125
            return self.results[self.run_name][0]['tag']
 
3126
        else:
 
3127
            for i in range(-1,-len(self.results[self.run_name])-1,-1):
 
3128
                tagRun = self.results[self.run_name][i]
 
3129
                if tagRun.pythia:
 
3130
                    return tagRun['tag']
 
3131
            
 
3132
            
 
3133
        
 
3134
        
 
3135
        
 
3136
        
 
3137
        
 
3138
 
 
3139
    ############################################################################
 
3140
    def find_model_name(self):
 
3141
        """ return the model name """
 
3142
        if hasattr(self, 'model_name'):
 
3143
            return self.model_name
 
3144
        
 
3145
        model = 'sm'
 
3146
        proc = []
 
3147
        for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')):
 
3148
            line = line.split('#')[0]
 
3149
            #line = line.split('=')[0]
 
3150
            if line.startswith('import') and 'model' in line:
 
3151
                model = line.split()[2]   
 
3152
                proc = []
 
3153
            elif line.startswith('generate'):
 
3154
                proc.append(line.split(None,1)[1])
 
3155
            elif line.startswith('add process'):
 
3156
                proc.append(line.split(None,2)[2])
 
3157
       
 
3158
        self.model = model
 
3159
        self.process = proc 
 
3160
        return model
 
3161
    
 
3162
    
 
3163
    ############################################################################
 
3164
    def check_nb_events(self):
 
3165
        """Find the number of event in the run_card, and check that this is not 
 
3166
        too large"""
 
3167
 
 
3168
        
 
3169
        nb_event = int(self.run_card['nevents'])
 
3170
        if nb_event > 1000000:
 
3171
            logger.warning("Attempting to generate more than 1M events")
 
3172
            logger.warning("Limiting number to 1M. Use multi_run for larger statistics.")
 
3173
            path = pjoin(self.me_dir, 'Cards', 'run_card.dat')
 
3174
            os.system(r"""perl -p -i.bak -e "s/\d+\s*=\s*nevents/1000000 = nevents/" %s""" \
 
3175
                                                                         % path)
 
3176
            self.run_card['nevents'] = 1000000
 
3177
 
 
3178
        return
 
3179
 
 
3180
  
 
3181
    ############################################################################    
 
3182
    def update_random(self):
 
3183
        """ change random number"""
 
3184
        
 
3185
        self.random += 3
 
3186
        if self.random > 30081*30081: # can't use too big random number
 
3187
            raise MadGraph5Error,\
 
3188
                  'Random seed too large ' + str(self.random) + ' > 30081*30081'
 
3189
 
 
3190
    ############################################################################
 
3191
    def save_random(self):
 
3192
        """save random number in appropirate file"""
 
3193
        
 
3194
        fsock = open(pjoin(self.me_dir, 'SubProcesses','randinit'),'w')
 
3195
        fsock.writelines('r=%s\n' % self.random)
 
3196
 
 
3197
    def do_quit(self, line):
 
3198
        """Not in help: exit """
 
3199
  
 
3200
        try:
 
3201
            os.remove(pjoin(self.me_dir,'RunWeb'))
 
3202
        except Exception:
 
3203
            pass
 
3204
        try:
 
3205
            self.store_result()
 
3206
        except Exception:
 
3207
            # If nothing runs they they are no result to update
 
3208
            pass
 
3209
        
 
3210
        try:
 
3211
            self.update_status('', level=None)
 
3212
        except Exception, error:        
 
3213
            pass
 
3214
        gen_crossxhtml.GenCardHTML(self.results)
 
3215
        return super(MadEventCmd, self).do_quit(line)
 
3216
    
 
3217
    # Aliases
 
3218
    do_EOF = do_quit
 
3219
    do_exit = do_quit
 
3220
        
 
3221
    ############################################################################
 
3222
    def treat_ckkw_matching(self):
 
3223
        """check for ckkw"""
 
3224
        
 
3225
        lpp1 = self.run_card['lpp1']
 
3226
        lpp2 = self.run_card['lpp2']
 
3227
        e1 = self.run_card['ebeam1']
 
3228
        e2 = self.run_card['ebeam2']
 
3229
        pd = self.run_card['pdlabel']
 
3230
        lha = self.run_card['lhaid']
 
3231
        xq = self.run_card['xqcut']
 
3232
        translation = {'e1': e1, 'e2':e2, 'pd':pd, 
 
3233
                       'lha':lha, 'xq':xq}
 
3234
 
 
3235
        if lpp1 or lpp2:
 
3236
            # Remove ':s from pd          
 
3237
            if pd.startswith("'"):
 
3238
                pd = pd[1:]
 
3239
            if pd.endswith("'"):
 
3240
                pd = pd[:-1]                
 
3241
 
 
3242
            if xq >2 or xq ==2:
 
3243
                xq = 2
 
3244
            
 
3245
            # find data file
 
3246
            if pd == "lhapdf":
 
3247
                issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(lha)s-%(xq)s.dat.gz'
 
3248
            else:
 
3249
                issudfile = 'lib/issudgrid-%(e1)s-%(e2)s-%(pd)s-%(xq)s.dat.gz'
 
3250
            if self.web:
 
3251
                issudfile = pjoin(self.webbin, issudfile % translation)
 
3252
            else:
 
3253
                issudfile = pjoin(self.me_dir, issudfile % translation)
 
3254
            
 
3255
            logger.info('Sudakov grid file: %s' % issudfile)
 
3256
            
 
3257
            # check that filepath exists
 
3258
            if os.path.exists(issudfile):
 
3259
                path = pjoin(self.me_dir, 'lib', 'issudgrid.dat')
 
3260
                os.system('gunzip -fc %s > %s' % (issudfile, path))
 
3261
            else:
 
3262
                msg = 'No sudakov grid file for parameter choice. Start to generate it. This might take a while'
 
3263
                logger.info(msg)
 
3264
                self.update_status('GENERATE SUDAKOF GRID', level='parton')
 
3265
                
 
3266
                for i in range(-2,6):
 
3267
                    self.cluster.submit('%s/gensudgrid ' % self.dirbin, 
 
3268
                                    arguments = [i],
 
3269
                                    cwd=self.me_dir, 
 
3270
                                    stdout=open(pjoin(self.me_dir, 'gensudgrid%s.log' % i,'w')))
 
3271
                self.monitor()
 
3272
                for i in range(-2,6):
 
3273
                    path = pjoin(self.me_dir, 'lib', 'issudgrid.dat')
 
3274
                    os.system('cat %s/gensudgrid%s.log >> %s' % (self.me_dir, path))
 
3275
                    os.system('gzip -fc %s > %s' % (path, issudfile))
 
3276
                                     
 
3277
    ############################################################################
 
3278
    def create_root_file(self, input='unweighted_events.lhe', 
 
3279
                                              output='unweighted_events.root' ):
 
3280
        """create the LHE root file """
 
3281
        self.update_status('Creating root files', level='parton')
 
3282
 
 
3283
        eradir = self.options['exrootanalysis_path']
 
3284
        try:
 
3285
            misc.call(['%s/ExRootLHEFConverter' % eradir, 
 
3286
                             input, output],
 
3287
                            cwd=pjoin(self.me_dir, 'Events'))
 
3288
        except Exception:
 
3289
            logger.warning('fail to produce Root output [problem with ExRootAnalysis]')
 
3290
 
 
3291
    ############################################################################
 
3292
    def ask_run_configuration(self, mode=None):
 
3293
        """Ask the question when launching generate_events/multi_run"""
 
3294
        
 
3295
        available_mode = ['0', '1']
 
3296
 
 
3297
        if self.options['pythia-pgs_path']:
 
3298
            available_mode.append('2')
 
3299
            available_mode.append('3')
 
3300
 
 
3301
            if self.options['delphes_path']:
 
3302
                available_mode.append('4')
 
3303
 
 
3304
        name = {'0': 'auto', '1': 'parton', '2':'pythia', '3':'pgs', '4':'delphes'}
 
3305
        options = []
 
3306
        for opt in available_mode:
 
3307
            value = int(opt)
 
3308
            tag = name[opt]
 
3309
            options += [opt, tag]
 
3310
            if value:
 
3311
                options.append(10+value)
 
3312
                options.append('%s+madspin' % tag)
 
3313
            
 
3314
        question = """Which programs do you want to run?
 
3315
  0 / auto    : running existing card
 
3316
  1 / parton  :  Madevent\n"""
 
3317
        if '2' in available_mode:
 
3318
            question += """  2 / pythia  : MadEvent + Pythia.
 
3319
  3 / pgs     : MadEvent + Pythia + PGS.\n"""
 
3320
        if '4' in available_mode:
 
3321
            question += """  4 / delphes :  MadEvent + Pythia + Delphes.\n"""
 
3322
        
 
3323
        question += '+10 / +madspin: adding MadSpin [before Pythia if asked]'
 
3324
        
 
3325
        if not self.force:
 
3326
            if not mode:
 
3327
                mode = self.ask(question, '0', options)
 
3328
        elif not mode:
 
3329
            mode = 'auto'
 
3330
            
 
3331
        if mode.isdigit():
 
3332
            value =  int(mode)
 
3333
            if value > 10:
 
3334
                # Running MadSpin
 
3335
                mode = str(value-10)
 
3336
                mode = name[mode] + '+madspin'
 
3337
            else:
 
3338
                mode = name[mode]
 
3339
        
 
3340
        auto = False
 
3341
        if mode == 'auto':
 
3342
            auto = True
 
3343
            if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pythia_card.dat')):
 
3344
                mode = 'parton'
 
3345
            elif os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
 
3346
                mode = 'pgs'
 
3347
            elif os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
 
3348
                mode = 'delphes'
 
3349
            else: 
 
3350
                mode = 'pythia'    
 
3351
            if os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')):
 
3352
                mode += '+madspin'         
 
3353
        logger.info('Will run in mode %s' % mode)
 
3354
                                                                     
 
3355
 
 
3356
        # Now that we know in which mode we are check that all the card
 
3357
        #exists (copy default if needed)
 
3358
 
 
3359
        cards = ['param_card.dat', 'run_card.dat']
 
3360
        if mode.endswith('+madspin'):
 
3361
            mode = mode[:-8]
 
3362
            cards.append('madspin_card.dat')
 
3363
        if mode in ['pythia', 'pgs', 'delphes']:
 
3364
            cards.append('pythia_card.dat')
 
3365
        if mode == 'pgs':
 
3366
            cards.append('pgs_card.dat')
 
3367
        elif mode == 'delphes':
 
3368
            cards.append('delphes_card.dat')
 
3369
            delphes3 = True
 
3370
            if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
 
3371
                delphes3 = False
 
3372
                cards.append('delphes_trigger.dat')
 
3373
        self.keep_cards(cards)
 
3374
        if self.force:
 
3375
            self.check_param_card(pjoin(self.me_dir,'Cards','param_card.dat' ))
 
3376
            return
 
3377
 
 
3378
        if auto:
 
3379
            self.ask_edit_cards(cards, mode='auto')
 
3380
        else:
 
3381
            self.ask_edit_cards(cards)
 
3382
        return
 
3383
    
 
3384
    ############################################################################
 
3385
    def ask_pythia_run_configuration(self, mode=None):
 
3386
        """Ask the question when launching pythia"""
 
3387
        
 
3388
        available_mode = ['0', '1', '2']
 
3389
        if self.options['delphes_path']:
 
3390
                available_mode.append('3')
 
3391
        name = {'0': 'auto', '1': 'pythia', '2':'pgs', '3':'delphes'}
 
3392
        options = available_mode + [name[val] for val in available_mode]
 
3393
        question = """Which programs do you want to run?
 
3394
    0 / auto    : running existing card
 
3395
    1 / pythia  : Pythia 
 
3396
    2 / pgs     : Pythia + PGS\n"""
 
3397
        if '3' in available_mode:
 
3398
            question += """    3 / delphes  : Pythia + Delphes.\n"""
 
3399
 
 
3400
        if not self.force:
 
3401
            if not mode:
 
3402
                mode = self.ask(question, '0', options)
 
3403
        elif not mode:
 
3404
            mode = 'auto'
 
3405
            
 
3406
        if mode.isdigit():
 
3407
            mode = name[mode]
 
3408
             
 
3409
        auto = False
 
3410
        if mode == 'auto':
 
3411
            auto = True
 
3412
            if os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
 
3413
                mode = 'pgs'
 
3414
            elif os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
 
3415
                mode = 'delphes'
 
3416
            else: 
 
3417
                mode = 'pythia'
 
3418
        logger.info('Will run in mode %s' % mode)
 
3419
                                               
 
3420
        # Now that we know in which mode we are check that all the card
 
3421
        #exists (copy default if needed) remove pointless one
 
3422
        cards = ['pythia_card.dat']
 
3423
        if mode == 'pgs':
 
3424
            cards.append('pgs_card.dat')
 
3425
        if mode == 'delphes':
 
3426
            cards.append('delphes_card.dat')
 
3427
            delphes3 = True
 
3428
            if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
 
3429
                delphes3 = False
 
3430
                cards.append('delphes_trigger.dat')
 
3431
        self.keep_cards(cards)
 
3432
        
 
3433
        if self.force:
 
3434
            return mode
 
3435
        
 
3436
        if auto:
 
3437
            self.ask_edit_cards(cards, mode='auto')
 
3438
        else:
 
3439
            self.ask_edit_cards(cards)
 
3440
        
 
3441
        return mode
 
3442
                
 
3443
  
 
3444
            
 
3445
    def check_param_card(self, path):
 
3446
        """Check that all the width are define in the param_card.
 
3447
        If some width are set on 'Auto', call the computation tools."""
 
3448
        
 
3449
        pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto''',re.I)
 
3450
        text = open(path).read()
 
3451
        pdg = pattern.findall(text)
 
3452
        if pdg:
 
3453
            logger.info('Computing the width set on auto in the param_card.dat')
 
3454
            self.do_compute_widths('%s %s' % (' '.join(pdg), path))
 
3455
 
 
3456
#===============================================================================
 
3457
# MadEventCmd
 
3458
#===============================================================================
 
3459
class MadEventCmdShell(MadEventCmd, cmd.CmdShell):
 
3460
    """The command line processor of MadGraph"""  
 
3461
 
 
3462
 
 
3463
 
 
3464
#===============================================================================
 
3465
# HELPING FUNCTION For Subprocesses
 
3466
#===============================================================================
 
3467
class SubProcesses(object):
 
3468
 
 
3469
    name_to_pdg = {}
 
3470
 
 
3471
    @classmethod
 
3472
    def clean(cls):
 
3473
        cls.name_to_pdg = {}
 
3474
    
 
3475
    @staticmethod
 
3476
    def get_subP(me_dir):
 
3477
        """return the list of Subprocesses"""
 
3478
        
 
3479
        out = []
 
3480
        for line in open(pjoin(me_dir,'SubProcesses', 'subproc.mg')):
 
3481
            if not line:
 
3482
                continue
 
3483
            name = line.strip()
 
3484
            if os.path.exists(pjoin(me_dir, 'SubProcesses', name)):
 
3485
                out.append(pjoin(me_dir, 'SubProcesses', name))
 
3486
        
 
3487
        return out
 
3488
        
 
3489
 
 
3490
 
 
3491
    @staticmethod
 
3492
    def get_subP_info(path):
 
3493
        """ return the list of processes with their name"""
 
3494
 
 
3495
        nb_sub = 0
 
3496
        names = {}
 
3497
        old_main = ''
 
3498
 
 
3499
        if not os.path.exists(os.path.join(path,'processes.dat')):
 
3500
            return SubProcesses.get_subP_info_v4(path)
 
3501
 
 
3502
        for line in open(os.path.join(path,'processes.dat')):
 
3503
            main = line[:8].strip()
 
3504
            if main == 'mirror':
 
3505
                main = old_main
 
3506
            if line[8:].strip() == 'none':
 
3507
                continue
 
3508
            else:
 
3509
                main = int(main)
 
3510
                old_main = main
 
3511
 
 
3512
            sub_proccess = line[8:]
 
3513
            nb_sub += sub_proccess.count(',') + 1
 
3514
            if main in names:
 
3515
                names[main] += [sub_proccess.split(',')]
 
3516
            else:
 
3517
                names[main]= [sub_proccess.split(',')]
 
3518
 
 
3519
        return names
 
3520
 
 
3521
    @staticmethod
 
3522
    def get_subP_info_v4(path):
 
3523
        """ return the list of processes with their name in case without grouping """
 
3524
 
 
3525
        nb_sub = 0
 
3526
        names = {'':[[]]}
 
3527
        path = os.path.join(path, 'auto_dsig.f')
 
3528
        found = 0
 
3529
        for line in open(path):
 
3530
            if line.startswith('C     Process:'):
 
3531
                found += 1
 
3532
                names[''][0].append(line[15:])
 
3533
            elif found >1:
 
3534
                break
 
3535
        return names
 
3536
 
 
3537
 
 
3538
    @staticmethod
 
3539
    def get_subP_ids(path):
 
3540
        """return the pdg codes of the particles present in the Subprocesses"""
 
3541
 
 
3542
        all_ids = []
 
3543
        for line in open(pjoin(path, 'leshouche.inc')):
 
3544
            if not 'IDUP' in line:
 
3545
                continue
 
3546
            particles = re.search("/([\d,-]+)/", line)
 
3547
            all_ids.append([int(p) for p in particles.group(1).split(',')])
 
3548
        return all_ids
 
3549
    
 
3550
    
 
3551
#===============================================================================                                                                              
 
3552
class GridPackCmd(MadEventCmd):
 
3553
    """The command for the gridpack --Those are not suppose to be use interactively--"""
 
3554
 
 
3555
    def __init__(self, me_dir = None, nb_event=0, seed=0, *completekey, **stdin):
 
3556
        """Initialize the command and directly run"""
 
3557
 
 
3558
        # Initialize properly
 
3559
        
 
3560
        MadEventCmd.__init__(self, me_dir, *completekey, **stdin)
 
3561
        self.run_mode = 0
 
3562
        self.random = seed
 
3563
        self.random_orig = self.random
 
3564
        self.options['automatic_html_opening'] = False
 
3565
        # Now it's time to run!
 
3566
        if me_dir and nb_event and seed:
 
3567
            self.launch(nb_event, seed)
 
3568
        else:
 
3569
            raise MadGraph5Error,\
 
3570
                  'Gridpack run failed: ' + str(me_dir) + str(nb_event) + \
 
3571
                  str(seed)
 
3572
 
 
3573
    def launch(self, nb_event, seed):
 
3574
        """ launch the generation for the grid """
 
3575
 
 
3576
        # 1) Restore the default data
 
3577
        logger.info('generate %s events' % nb_event)
 
3578
        self.set_run_name('GridRun_%s' % seed)
 
3579
        self.update_status('restoring default data', level=None)
 
3580
        misc.call([pjoin(self.me_dir,'bin','internal','restore_data'),
 
3581
                         'default'],
 
3582
            cwd=self.me_dir)
 
3583
 
 
3584
        # 2) Run the refine for the grid
 
3585
        self.update_status('Generating Events', level=None)
 
3586
        #misc.call([pjoin(self.me_dir,'bin','refine4grid'),
 
3587
        #                str(nb_event), '0', 'Madevent','1','GridRun_%s' % seed],
 
3588
        #                cwd=self.me_dir)
 
3589
        self.refine4grid(nb_event)
 
3590
 
 
3591
        # 3) Combine the events/pythia/...
 
3592
        self.exec_cmd('combine_events')
 
3593
        self.exec_cmd('store_events')
 
3594
        self.print_results_in_shell(self.results.current)
 
3595
 
 
3596
    def refine4grid(self, nb_event):
 
3597
        """Special refine for gridpack run."""
 
3598
        self.nb_refine += 1
 
3599
        
 
3600
        precision = nb_event
 
3601
 
 
3602
        # initialize / remove lhapdf mode
 
3603
        # self.configure_directory() # All this has been done before
 
3604
        self.cluster_mode = 0 # force single machine
 
3605
 
 
3606
        # Store seed in randinit file, to be read by ranmar.f
 
3607
        self.save_random()
 
3608
        
 
3609
        self.update_status('Refine results to %s' % precision, level=None)
 
3610
        logger.info("Using random number seed offset = %s" % self.random)
 
3611
        
 
3612
        self.total_jobs = 0
 
3613
        subproc = [P for P in os.listdir(pjoin(self.me_dir,'SubProcesses')) if 
 
3614
                   P.startswith('P') and os.path.isdir(pjoin(self.me_dir,'SubProcesses', P))]
 
3615
        devnull = open(os.devnull, 'w')
 
3616
        for nb_proc,subdir in enumerate(subproc):
 
3617
            subdir = subdir.strip()
 
3618
            Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
 
3619
            bindir = pjoin(os.path.relpath(self.dirbin, Pdir))
 
3620
                           
 
3621
            logger.info('    %s ' % subdir)
 
3622
            # clean previous run
 
3623
            for match in glob.glob(pjoin(Pdir, '*ajob*')):
 
3624
                if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
 
3625
                    os.remove(pjoin(Pdir, match))
 
3626
            
 
3627
 
 
3628
            logfile = pjoin(Pdir, 'gen_ximprove.log')
 
3629
            proc = misc.Popen([pjoin(bindir, 'gen_ximprove')],
 
3630
                                    stdin=subprocess.PIPE,
 
3631
                                    stdout=open(logfile,'w'),
 
3632
                                    cwd=Pdir)
 
3633
            proc.communicate('%s 1 F\n' % (precision))
 
3634
 
 
3635
            if os.path.exists(pjoin(Pdir, 'ajob1')):
 
3636
                alljobs = glob.glob(pjoin(Pdir,'ajob*'))
 
3637
                nb_tot = len(alljobs)            
 
3638
                self.total_jobs += nb_tot
 
3639
                for i, job in enumerate(alljobs):
 
3640
                    job = os.path.basename(job)
 
3641
                    self.launch_job('%s' % job, cwd=Pdir, remaining=(nb_tot-i-1), 
 
3642
                             run_type='Refine number %s on %s (%s/%s)' %
 
3643
                             (self.nb_refine, subdir, nb_proc+1, len(subproc)))
 
3644
                    if os.path.exists(pjoin(self.me_dir,'error')):
 
3645
                        self.monitor(html=True)
 
3646
                        raise MadEventError, \
 
3647
                            'Error detected in dir %s: %s' % \
 
3648
                            (Pdir, open(pjoin(self.me_dir,'error')).read())
 
3649
        self.monitor(run_type='All job submitted for refine number %s' % 
 
3650
                                                                 self.nb_refine)
 
3651
        
 
3652
        self.update_status("Combining runs", level='parton')
 
3653
        try:
 
3654
            os.remove(pjoin(Pdir, 'combine_runs.log'))
 
3655
        except Exception:
 
3656
            pass
 
3657
        
 
3658
        bindir = pjoin(os.path.relpath(self.dirbin, pjoin(self.me_dir,'SubProcesses')))
 
3659
        combine_runs.CombineRuns(self.me_dir)
 
3660
        
 
3661
        #update html output
 
3662
        cross, error = sum_html.make_all_html_results(self)
 
3663
        self.results.add_detail('cross', cross)
 
3664
        self.results.add_detail('error', error)
 
3665
        
 
3666
        
 
3667
        self.update_status('finish refine', 'parton', makehtml=False)
 
3668
        devnull.close()
 
3669
 
 
3670
 
 
3671
 
 
3672
AskforEditCard = common_run.AskforEditCard
 
3673
 
 
3674