Advertisement
Guest User

Untitled

a guest
Mar 31st, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 185.92 KB | None | 0 0
  1. ################################################################################
  2. #
  3. # Copyright (c) 2011 The MadGraph5_aMC@NLO Development team and Contributors
  4. #
  5. # This file is a part of the MadGraph5_aMC@NLO 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 MadGraph5_aMC@NLO license which should accompany this
  10. # distribution.
  11. #
  12. # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch
  13. #
  14. ################################################################################
  15.  
  16. from __future__ import division
  17. import collections
  18. import copy
  19. import logging
  20. import numbers
  21. import os
  22. import sys
  23. import re
  24. import math
  25. import StringIO
  26.  
  27. pjoin = os.path.join
  28.  
  29. try:
  30.     import madgraph
  31. except ImportError:
  32.     MADEVENT = True
  33.     from internal import MadGraph5Error, InvalidCmd
  34.     import internal.file_writers as file_writers
  35.     import internal.files as files
  36.     import internal.check_param_card as param_card_reader
  37.     import internal.misc as misc
  38.     MEDIR = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
  39.     MEDIR = os.path.split(MEDIR)[0]
  40. else:
  41.     MADEVENT = False
  42.     import madgraph.various.misc as misc
  43.     import madgraph.iolibs.file_writers as file_writers
  44.     import madgraph.iolibs.files as files
  45.     import models.check_param_card as param_card_reader
  46.     from madgraph import MG5DIR, MadGraph5Error, InvalidCmd
  47.  
  48.  
  49. logger = logging.getLogger('madevent.cards')
  50.  
  51. # A placeholder class to store unknown parameters with undecided format
  52. class UnknownType(str):
  53.     pass
  54.  
  55. #dict
  56. class Banner(dict):
  57.     """ """
  58.  
  59.     ordered_items = ['mgversion', 'mg5proccard', 'mgproccard', 'mgruncard',
  60.                      'slha','initrwgt','mggenerationinfo', 'mgpythiacard', 'mgpgscard',
  61.                      'mgdelphescard', 'mgdelphestrigger','mgshowercard',
  62.                      'ma5card_parton','ma5card_hadron','run_settings']
  63.  
  64.     capitalized_items = {
  65.             'mgversion': 'MGVersion',
  66.             'mg5proccard': 'MG5ProcCard',
  67.             'mgproccard': 'MGProcCard',
  68.             'mgruncard': 'MGRunCard',
  69.             'ma5card_parton' : 'MA5Card_parton',
  70.             'ma5card_hadron' : 'MA5Card_hadron',            
  71.             'mggenerationinfo': 'MGGenerationInfo',
  72.             'mgpythiacard': 'MGPythiaCard',
  73.             'mgpgscard': 'MGPGSCard',
  74.             'mgdelphescard': 'MGDelphesCard',
  75.             'mgdelphestrigger': 'MGDelphesTrigger',
  76.             'mgshowercard': 'MGShowerCard' }
  77.    
  78.     forbid_cdata = ['initrwgt']
  79.    
  80.     def __init__(self, banner_path=None):
  81.         """ """
  82.  
  83.         if isinstance(banner_path, Banner):
  84.             dict.__init__(self, banner_path)
  85.             self.lhe_version = banner_path.lhe_version
  86.             return    
  87.         else:
  88.             dict.__init__(self)
  89.        
  90.         #Look at the version
  91.         if MADEVENT:
  92.             self['mgversion'] = '#%s\n' % open(pjoin(MEDIR, 'MGMEVersion.txt')).read()
  93.         else:
  94.             info = misc.get_pkg_info()
  95.             self['mgversion'] = info['version']+'\n'
  96.        
  97.         self.lhe_version = None
  98.  
  99.    
  100.         if banner_path:
  101.             self.read_banner(banner_path)
  102.  
  103.     ############################################################################
  104.     #  READ BANNER
  105.     ############################################################################
  106.     pat_begin=re.compile('<(?P<name>\w*)>')
  107.     pat_end=re.compile('</(?P<name>\w*)>')
  108.  
  109.     tag_to_file={'slha':'param_card.dat',
  110.       'mgruncard':'run_card.dat',
  111.       'mgpythiacard':'pythia_card.dat',
  112.       'mgpgscard' : 'pgs_card.dat',
  113.       'mgdelphescard':'delphes_card.dat',      
  114.       'mgdelphestrigger':'delphes_trigger.dat',
  115.       'mg5proccard':'proc_card_mg5.dat',
  116.       'mgproccard': 'proc_card.dat',
  117.       'init': '',
  118.       'mggenerationinfo':'',
  119.       'scalesfunctionalform':'',
  120.       'montecarlomasses':'',
  121.       'initrwgt':'',
  122.       'madspin':'madspin_card.dat',
  123.       'mgshowercard':'shower_card.dat',
  124.       'pythia8':'pythia8_card.dat',
  125.       'ma5card_parton':'madanalysis5_parton_card.dat',
  126.       'ma5card_hadron':'madanalysis5_hadron_card.dat',      
  127.       'run_settings':''
  128.       }
  129.    
  130.     def read_banner(self, input_path):
  131.         """read a banner"""
  132.  
  133.         if isinstance(input_path, str):
  134.             if input_path.find('\n') ==-1:
  135.                 input_path = open(input_path)
  136.             else:
  137.                 def split_iter(string):
  138.                     return (x.groups(0)[0] for x in re.finditer(r"([^\n]*\n)", string, re.DOTALL))
  139.                 input_path = split_iter(input_path)
  140.                
  141.         text = ''
  142.         store = False
  143.         for line in input_path:
  144.             if self.pat_begin.search(line):
  145.                 if self.pat_begin.search(line).group('name').lower() in self.tag_to_file:
  146.                     tag = self.pat_begin.search(line).group('name').lower()
  147.                     store = True
  148.                     continue
  149.             if store and self.pat_end.search(line):
  150.                 if tag == self.pat_end.search(line).group('name').lower():
  151.                     self[tag] = text
  152.                     text = ''
  153.                     store = False
  154.             if store and not line.startswith(('<![CDATA[',']]>')):
  155.                 if line.endswith('\n'):
  156.                     text += line
  157.                 else:
  158.                     text += '%s%s' % (line, '\n')
  159.                
  160.             #reaching end of the banner in a event file avoid to read full file
  161.             if "</init>" in line:
  162.                 break
  163.             elif "<event>" in line:
  164.                 break
  165.    
  166.     def __getattribute__(self, attr):
  167.         """allow auto-build for the run_card/param_card/... """
  168.         try:
  169.             return super(Banner, self).__getattribute__(attr)
  170.         except:
  171.             if attr not in ['run_card', 'param_card', 'slha', 'mgruncard', 'mg5proccard', 'mgshowercard', 'foanalyse']:
  172.                 raise
  173.             return self.charge_card(attr)
  174.  
  175.  
  176.    
  177.     def change_lhe_version(self, version):
  178.         """change the lhe version associate to the banner"""
  179.    
  180.         version = float(version)
  181.         if version < 3:
  182.             version = 1
  183.         elif version > 3:
  184.             raise Exception, "Not Supported version"
  185.         self.lhe_version = version
  186.    
  187.     def get_cross(self, witherror=False):
  188.         """return the cross-section of the file"""
  189.  
  190.         if "init" not in self:
  191.             raise Exception
  192.        
  193.         text = self["init"].split('\n')
  194.         cross = 0
  195.         error = 0
  196.         for line in text:
  197.             s = line.split()
  198.             if len(s)==4:
  199.                 cross += float(s[0])
  200.                 if witherror:
  201.                     error += float(s[1])**2
  202.         if not witherror:
  203.             return cross
  204.         else:
  205.             return cross, math.sqrt(error)
  206.        
  207.  
  208.     def scale_init_cross(self, ratio):
  209.         """modify the init information with the associate scale"""
  210.  
  211.         assert "init" in self
  212.        
  213.         all_lines = self["init"].split('\n')
  214.         new_data = []
  215.         new_data.append(all_lines[0])
  216.         for i in range(1, len(all_lines)):
  217.             line = all_lines[i]
  218.             split = line.split()
  219.             if len(split) == 4:
  220.                 xsec, xerr, xmax, pid = split
  221.             else:
  222.                 new_data += all_lines[i:]
  223.                 break
  224.             pid = int(pid)
  225.            
  226.             line = "   %+13.7e %+13.7e %+13.7e %i" % \
  227.                 (ratio*float(xsec), ratio* float(xerr), ratio*float(xmax), pid)
  228.             new_data.append(line)
  229.         self['init'] = '\n'.join(new_data)
  230.    
  231.     def get_pdg_beam(self):
  232.         """return the pdg of each beam"""
  233.        
  234.         assert "init" in self
  235.        
  236.         all_lines = self["init"].split('\n')
  237.         pdg1,pdg2,_ = all_lines[0].split(None, 2)
  238.         return int(pdg1), int(pdg2)
  239.    
  240.     def load_basic(self, medir):
  241.         """ Load the proc_card /param_card and run_card """
  242.        
  243.         self.add(pjoin(medir,'Cards', 'param_card.dat'))
  244.         self.add(pjoin(medir,'Cards', 'run_card.dat'))
  245.         if os.path.exists(pjoin(medir, 'SubProcesses', 'procdef_mg5.dat')):
  246.             self.add(pjoin(medir,'SubProcesses', 'procdef_mg5.dat'))
  247.             self.add(pjoin(medir,'Cards', 'proc_card_mg5.dat'))
  248.         else:
  249.             self.add(pjoin(medir,'Cards', 'proc_card.dat'))
  250.        
  251.     def change_seed(self, seed):
  252.         """Change the seed value in the banner"""
  253.         #      0       = iseed
  254.         p = re.compile(r'''^\s*\d+\s*=\s*iseed''', re.M)
  255.         new_seed_str = " %s = iseed" % seed
  256.         self['mgruncard'] = p.sub(new_seed_str, self['mgruncard'])
  257.    
  258.     def add_generation_info(self, cross, nb_event):
  259.         """add info on MGGeneration"""
  260.        
  261.         text = """
  262. #  Number of Events        :       %s
  263. #  Integrated weight (pb)  :       %s
  264. """ % (nb_event, cross)
  265.         self['MGGenerationInfo'] = text
  266.    
  267.     ############################################################################
  268.     #  SPLIT BANNER
  269.     ############################################################################
  270.     def split(self, me_dir, proc_card=True):
  271.         """write the banner in the Cards directory.
  272.        proc_card argument is present to avoid the overwrite of proc_card
  273.        information"""
  274.  
  275.         for tag, text in self.items():
  276.             if tag == 'mgversion':
  277.                 continue
  278.             if not proc_card and tag in ['mg5proccard','mgproccard']:
  279.                 continue
  280.             if not self.tag_to_file[tag]:
  281.                 continue
  282.             ff = open(pjoin(me_dir, 'Cards', self.tag_to_file[tag]), 'w')
  283.             ff.write(text)
  284.             ff.close()
  285.  
  286.  
  287.     ############################################################################
  288.     #  WRITE BANNER
  289.     ############################################################################
  290.     def check_pid(self, pid2label):
  291.         """special routine removing width/mass of particles not present in the model
  292.        This is usefull in case of loop model card, when we want to use the non
  293.        loop model."""
  294.        
  295.         if not hasattr(self, 'param_card'):
  296.             self.charge_card('slha')
  297.            
  298.         for tag in ['mass', 'decay']:
  299.             block = self.param_card.get(tag)
  300.             for data in block:
  301.                 pid = data.lhacode[0]
  302.                 if pid not in pid2label.keys():
  303.                     block.remove((pid,))
  304.  
  305.     def get_lha_strategy(self):
  306.         """get the lha_strategy: how the weight have to be handle by the shower"""
  307.        
  308.         if not self["init"]:
  309.             raise Exception, "No init block define"
  310.        
  311.         data = self["init"].split('\n')[0].split()
  312.         if len(data) != 10:
  313.             misc.sprint(len(data), self['init'])
  314.             raise Exception, "init block has a wrong format"
  315.         return int(float(data[-2]))
  316.        
  317.     def set_lha_strategy(self, value):
  318.         """set the lha_strategy: how the weight have to be handle by the shower"""
  319.        
  320.         if not (-4 <= int(value) <= 4):
  321.             raise Exception, "wrong value for lha_strategy", value
  322.         if not self["init"]:
  323.             raise Exception, "No init block define"
  324.        
  325.         all_lines = self["init"].split('\n')
  326.         data = all_lines[0].split()
  327.         if len(data) != 10:
  328.             misc.sprint(len(data), self['init'])
  329.             raise Exception, "init block has a wrong format"
  330.         data[-2] = '%s' % value
  331.         all_lines[0] = ' '.join(data)
  332.         self['init'] = '\n'.join(all_lines)
  333.  
  334.  
  335.     def modify_init_cross(self, cross):
  336.         """modify the init information with the associate cross-section"""
  337.         assert isinstance(cross, dict)
  338. #        assert "all" in cross
  339.         assert "init" in self
  340.        
  341.         cross = dict(cross)
  342.         for key in cross.keys():
  343.             if isinstance(key, str) and key.isdigit() and int(key) not in cross:
  344.                 cross[int(key)] = cross[key]
  345.        
  346.        
  347.         all_lines = self["init"].split('\n')
  348.         new_data = []
  349.         new_data.append(all_lines[0])
  350.         for i in range(1, len(all_lines)):
  351.             line = all_lines[i]
  352.             split = line.split()
  353.             if len(split) == 4:
  354.                 xsec, xerr, xmax, pid = split
  355.             else:
  356.                 new_data += all_lines[i:]
  357.                 break
  358.             if int(pid) not in cross:
  359.                 raise Exception
  360.             pid = int(pid)
  361.             if float(xsec):
  362.                 ratio = cross[pid]/float(xsec)
  363.             else:
  364.                 ratio = 0
  365.             line = "   %+13.7e %+13.7e %+13.7e %i" % \
  366.                 (float(cross[pid]), ratio* float(xerr), ratio*float(xmax), pid)
  367.             new_data.append(line)
  368.         self['init'] = '\n'.join(new_data)
  369.                
  370.     ############################################################################
  371.     #  WRITE BANNER
  372.     ############################################################################
  373.     def write(self, output_path, close_tag=True, exclude=[]):
  374.         """write the banner"""
  375.        
  376.         if isinstance(output_path, str):
  377.             ff = open(output_path, 'w')
  378.         else:
  379.             ff = output_path
  380.            
  381.         if MADEVENT:
  382.             header = open(pjoin(MEDIR, 'Source', 'banner_header.txt')).read()
  383.         else:
  384.             header = open(pjoin(MG5DIR,'Template', 'LO', 'Source', 'banner_header.txt')).read()
  385.            
  386.         if not self.lhe_version:
  387.             self.lhe_version = self.get('run_card', 'lhe_version', default=1.0)
  388.             if float(self.lhe_version) < 3:
  389.                 self.lhe_version = 1.0
  390.        
  391.         ff.write(header % { 'version':float(self.lhe_version)})
  392.  
  393.  
  394.         for tag in [t for t in self.ordered_items if t in self.keys()]+ \
  395.             [t for t in self.keys() if t not in self.ordered_items]:
  396.             if tag in ['init'] or tag in exclude:
  397.                 continue
  398.             capitalized_tag = self.capitalized_items[tag] if tag in self.capitalized_items else tag
  399.             start_data, stop_data = '', ''
  400.             if capitalized_tag not in self.forbid_cdata and \
  401.                                           ('<' in self[tag] or '@' in self[tag]):
  402.                 start_data = '\n<![CDATA['
  403.                 stop_data = ']]>\n'
  404.             ff.write('<%(tag)s>%(start_data)s\n%(text)s\n%(stop_data)s</%(tag)s>\n' % \
  405.                      {'tag':capitalized_tag, 'text':self[tag].strip(),
  406.                       'start_data': start_data, 'stop_data':stop_data})
  407.        
  408.        
  409.         if not '/header' in exclude:
  410.             ff.write('</header>\n')    
  411.  
  412.         if 'init' in self and not 'init' in exclude:
  413.             text = self['init']
  414.             ff.write('<%(tag)s>\n%(text)s\n</%(tag)s>\n' % \
  415.                      {'tag':'init', 'text':text.strip()})  
  416.         if close_tag:          
  417.             ff.write('</LesHouchesEvents>\n')
  418.         return ff
  419.        
  420.        
  421.     ############################################################################
  422.     # BANNER
  423.     ############################################################################
  424.     def add(self, path, tag=None):
  425.         """Add the content of the file to the banner"""
  426.        
  427.         if not tag:
  428.             card_name = os.path.basename(path)
  429.             if 'param_card' in card_name:
  430.                 tag = 'slha'
  431.             elif 'run_card' in card_name:
  432.                 tag = 'MGRunCard'
  433.             elif 'pythia_card' in card_name:
  434.                 tag = 'MGPythiaCard'
  435.             elif 'pythia8_card' in card_name or 'pythia8.cmd' in card_name:
  436.                 tag = 'MGPythiaCard'
  437.             elif 'pgs_card' in card_name:
  438.                 tag = 'MGPGSCard'
  439.             elif 'delphes_card' in card_name:
  440.                 tag = 'MGDelphesCard'
  441.             elif 'delphes_trigger' in card_name:
  442.                 tag = 'MGDelphesTrigger'
  443.             elif 'proc_card_mg5' in card_name:
  444.                 tag = 'MG5ProcCard'
  445.             elif 'proc_card' in card_name:
  446.                 tag = 'MGProcCard'
  447.             elif 'procdef_mg5' in card_name:
  448.                 tag = 'MGProcCard'
  449.             elif 'shower_card' in card_name:
  450.                 tag = 'MGShowerCard'
  451.             elif 'madspin_card' in card_name:
  452.                 tag = 'madspin'
  453.             elif 'FO_analyse_card' in card_name:
  454.                 tag = 'foanalyse'
  455.             elif 'reweight_card' in card_name:
  456.                 tag='reweight_card'
  457.             elif 'madanalysis5_parton_card' in card_name:
  458.                 tag='MA5Card_parton'
  459.             elif 'madanalysis5_hadron_card' in card_name:
  460.                 tag='MA5Card_hadron'
  461.             else:
  462.                 raise Exception, 'Impossible to know the type of the card'
  463.  
  464.             self.add_text(tag.lower(), open(path).read())
  465.  
  466.     def add_text(self, tag, text):
  467.         """Add the content of the file to the banner"""
  468.  
  469.         if tag == 'param_card':
  470.             tag = 'slha'
  471.         elif tag == 'run_card':
  472.             tag = 'mgruncard'
  473.         elif tag == 'proc_card':
  474.             tag = 'mg5proccard'
  475.         elif tag == 'shower_card':
  476.             tag = 'mgshowercard'
  477.         elif tag == 'FO_analyse_card':
  478.             tag = 'foanalyse'
  479.        
  480.         self[tag.lower()] = text
  481.    
  482.    
  483.     def charge_card(self, tag):
  484.         """Build the python object associated to the card"""
  485.        
  486.         if tag in ['param_card', 'param']:
  487.             tag = 'slha'
  488.         elif tag  in ['run_card', 'run']:
  489.             tag = 'mgruncard'
  490.         elif tag == 'proc_card':
  491.             tag = 'mg5proccard'
  492.         elif tag == 'shower_card':
  493.             tag = 'mgshowercard'
  494.         elif tag == 'FO_analyse_card':
  495.             tag = 'foanalyse'
  496.  
  497.         assert tag in ['slha', 'mgruncard', 'mg5proccard', 'mgshowercard', 'foanalyse'], 'invalid card %s' % tag
  498.        
  499.         if tag == 'slha':
  500.             param_card = self[tag].split('\n')
  501.             self.param_card = param_card_reader.ParamCard(param_card)
  502.             return self.param_card
  503.         elif tag == 'mgruncard':
  504.             self.run_card = RunCard(self[tag])
  505.             return self.run_card
  506.         elif tag == 'mg5proccard':
  507.             proc_card = self[tag].split('\n')
  508.             self.proc_card = ProcCard(proc_card)
  509.             return self.proc_card
  510.         elif tag =='mgshowercard':
  511.             shower_content = self[tag]
  512.             if MADEVENT:
  513.                 import internal.shower_card as shower_card
  514.             else:
  515.                 import madgraph.various.shower_card as shower_card
  516.             self.shower_card = shower_card.ShowerCard(shower_content, True)
  517.             # set testing to false (testing = true allow to init using
  518.             #  the card content instead of the card path"
  519.             self.shower_card.testing = False
  520.             return self.shower_card
  521.         elif tag =='foanalyse':
  522.             analyse_content = self[tag]
  523.             if MADEVENT:
  524.                 import internal.FO_analyse_card as FO_analyse_card
  525.             else:
  526.                 import madgraph.various.FO_analyse_card as FO_analyse_card
  527.             # set testing to false (testing = true allow to init using
  528.             #  the card content instead of the card path"
  529.             self.FOanalyse_card = FO_analyse_card.FOAnalyseCard(analyse_content, True)
  530.             self.FOanalyse_card.testing = False
  531.             return self.FOanalyse_card
  532.        
  533.  
  534.     def get_detail(self, tag, *arg, **opt):
  535.         """return a specific """
  536.                
  537.         if tag in ['param_card', 'param']:
  538.             tag = 'slha'
  539.             attr_tag = 'param_card'
  540.         elif tag in ['run_card', 'run']:
  541.             tag = 'mgruncard'
  542.             attr_tag = 'run_card'
  543.         elif tag == 'proc_card':
  544.             tag = 'mg5proccard'
  545.             attr_tag = 'proc_card'
  546.         elif tag == 'model':
  547.             tag = 'mg5proccard'
  548.             attr_tag = 'proc_card'
  549.             arg = ('model',)
  550.         elif tag == 'generate':
  551.             tag = 'mg5proccard'
  552.             attr_tag = 'proc_card'
  553.             arg = ('generate',)
  554.         elif tag == 'shower_card':
  555.             tag = 'mgshowercard'
  556.             attr_tag = 'shower_card'
  557.         assert tag in ['slha', 'mgruncard', 'mg5proccard', 'shower_card'], '%s not recognized' % tag
  558.        
  559.         if not hasattr(self, attr_tag):
  560.             self.charge_card(attr_tag)
  561.  
  562.         card = getattr(self, attr_tag)
  563.         if len(arg) == 0:
  564.             return card
  565.         elif len(arg) == 1:
  566.             if tag == 'mg5proccard':
  567.                 try:
  568.                     return card.get(arg[0])
  569.                 except KeyError, error:
  570.                     if 'default' in opt:
  571.                         return opt['default']
  572.                     else:
  573.                         raise
  574.             try:
  575.                 return card[arg[0]]
  576.             except KeyError:
  577.                 if 'default' in opt:
  578.                     return opt['default']
  579.                 else:
  580.                     raise                
  581.         elif len(arg) == 2 and tag == 'slha':
  582.             try:
  583.                 return card[arg[0]].get(arg[1:])
  584.             except KeyError:
  585.                 if 'default' in opt:
  586.                     return opt['default']
  587.                 else:
  588.                     raise  
  589.         elif len(arg) == 0:
  590.             return card
  591.         else:
  592.             raise Exception, "Unknow command"
  593.    
  594.     #convenient alias
  595.     get = get_detail
  596.    
  597.     def set(self, card, *args):
  598.         """modify one of the cards"""
  599.  
  600.         if tag == 'param_card':
  601.             tag = 'slha'
  602.             attr_tag = 'param_card'
  603.         elif tag == 'run_card':
  604.             tag = 'mgruncard'
  605.             attr_tag = 'run_card'
  606.         elif tag == 'proc_card':
  607.             tag = 'mg5proccard'
  608.             attr_tag = 'proc_card'
  609.         elif tag == 'model':
  610.             tag = 'mg5proccard'
  611.             attr_tag = 'proc_card'
  612.             arg = ('model',)
  613.         elif tag == 'generate':
  614.             tag = 'mg5proccard'
  615.             attr_tag = 'proc_card'
  616.             arg = ('generate',)
  617.         elif tag == 'shower_card':
  618.             tag = 'mgshowercard'
  619.             attr_tag = 'shower_card'
  620.         assert tag in ['slha', 'mgruncard', 'mg5proccard', 'shower_card'], 'not recognized'
  621.        
  622.         if not hasattr(self, attr_tag):
  623.             self.charge_card(attr_tag)
  624.            
  625.         card = getattr(self, attr_tag)
  626.         if len(args) ==2:
  627.             if tag == 'mg5proccard':
  628.                 card.info[args[0]] = args[-1]
  629.             else:
  630.                 card[args[0]] = args[1]
  631.         else:
  632.             card[args[:-1]] = args[-1]
  633.        
  634.    
  635.     @misc.multiple_try()
  636.     def add_to_file(self, path, seed=None, out=None):
  637.         """Add the banner to a file and change the associate seed in the banner"""
  638.  
  639.         if seed is not None:
  640.             self.set("run_card", "iseed", seed)
  641.        
  642.         if not out:
  643.             path_out = "%s.tmp" % path
  644.         else:
  645.             path_out = out
  646.        
  647.         ff = self.write(path_out, close_tag=False,
  648.                         exclude=['MGGenerationInfo', '/header', 'init'])
  649.         ff.write("## END BANNER##\n")
  650.         if self.lhe_version >= 3:
  651.         #add the original content
  652.             [ff.write(line) if not line.startswith("<generator name='MadGraph5_aMC@NLO'")
  653.                         else ff.write("<generator name='MadGraph5_aMC@NLO' version='%s'>" % self['mgversion'][:-1])
  654.                         for line in open(path)]
  655.         else:
  656.             [ff.write(line) for line in open(path)]
  657.         ff.write("</LesHouchesEvents>\n")
  658.         ff.close()
  659.         if out:
  660.             os.remove(path)
  661.         else:
  662.             files.mv(path_out, path)
  663.  
  664.  
  665.        
  666. def split_banner(banner_path, me_dir, proc_card=True):
  667.     """a simple way to split a banner"""
  668.    
  669.     banner = Banner(banner_path)
  670.     banner.split(me_dir, proc_card)
  671.    
  672. def recover_banner(results_object, level, run=None, tag=None):
  673.     """as input we receive a gen_crossxhtml.AllResults object.
  674.       This define the current banner and load it
  675.    """
  676.    
  677.     if not run:
  678.         try:
  679.             _run = results_object.current['run_name']  
  680.             _tag = results_object.current['tag']
  681.         except Exception:
  682.             return Banner()
  683.     else:
  684.         _run = run
  685.     if not tag:
  686.         try:    
  687.             _tag = results_object[run].tags[-1]
  688.         except Exception,error:
  689.             return Banner()      
  690.     else:
  691.         _tag = tag
  692.                                          
  693.     path = results_object.path
  694.     banner_path = pjoin(path,'Events',run,'%s_%s_banner.txt' % (run, tag))
  695.    
  696.     if not os.path.exists(banner_path):
  697.         if level != "parton" and tag != _tag:
  698.             return recover_banner(results_object, level, _run, results_object[_run].tags[0])
  699.         elif level == 'parton':
  700.             paths = [pjoin(path,'Events',run, 'unweighted_events.lhe.gz'),
  701.                      pjoin(path,'Events',run, 'unweighted_events.lhe'),
  702.                      pjoin(path,'Events',run, 'events.lhe.gz'),
  703.                      pjoin(path,'Events',run, 'events.lhe')]
  704.             for p in paths:
  705.                 if os.path.exists(p):
  706.                     if MADEVENT:
  707.                         import internal.lhe_parser as lhe_parser
  708.                     else:
  709.                         import madgraph.various.lhe_parser as lhe_parser
  710.                     lhe = lhe_parser.EventFile(p)
  711.                     return Banner(lhe.banner)
  712.  
  713.         # security if the banner was remove (or program canceled before created it)
  714.         return Banner()  
  715.     banner = Banner(banner_path)
  716.    
  717.    
  718.    
  719.     if level == 'pythia':
  720.         if 'mgpythiacard' in banner:
  721.             del banner['mgpythiacard']
  722.     if level in ['pythia','pgs','delphes']:
  723.         for tag in ['mgpgscard', 'mgdelphescard', 'mgdelphestrigger']:
  724.             if tag in banner:
  725.                 del banner[tag]
  726.     return banner
  727.    
  728. class InvalidRunCard(InvalidCmd):
  729.     pass
  730.  
  731. class ProcCard(list):
  732.     """Basic Proccard object"""
  733.    
  734.     history_header = \
  735.         '#************************************************************\n' + \
  736.         '#*                     MadGraph5_aMC@NLO                    *\n' + \
  737.         '#*                                                          *\n' + \
  738.         "#*                *                       *                 *\n" + \
  739.         "#*                  *        * *        *                   *\n" + \
  740.         "#*                    * * * * 5 * * * *                     *\n" + \
  741.         "#*                  *        * *        *                   *\n" + \
  742.         "#*                *                       *                 *\n" + \
  743.         "#*                                                          *\n" + \
  744.         "#*                                                          *\n" + \
  745.         "%(info_line)s" +\
  746.         "#*                                                          *\n" + \
  747.         "#*    The MadGraph5_aMC@NLO Development Team - Find us at   *\n" + \
  748.         "#*    https://server06.fynu.ucl.ac.be/projects/madgraph     *\n" + \
  749.         '#*                                                          *\n' + \
  750.         '#************************************************************\n' + \
  751.         '#*                                                          *\n' + \
  752.         '#*               Command File for MadGraph5_aMC@NLO         *\n' + \
  753.         '#*                                                          *\n' + \
  754.         '#*     run as ./bin/mg5_aMC  filename                       *\n' + \
  755.         '#*                                                          *\n' + \
  756.         '#************************************************************\n'
  757.    
  758.    
  759.    
  760.    
  761.     def __init__(self, init=None):
  762.         """ initialize a basic proc_card"""
  763.         self.info = {'model': 'sm', 'generate':None,
  764.                      'full_model_line':'import model sm'}
  765.         list.__init__(self)
  766.         if init:
  767.             self.read(init)
  768.  
  769.            
  770.     def read(self, init):
  771.         """read the proc_card and save the information"""
  772.        
  773.         if isinstance(init, str): #path to file
  774.             init = file(init, 'r')
  775.        
  776.         store_line = ''
  777.         for line in init:
  778.             line = line.rstrip()
  779.             if line.endswith('\\'):
  780.                 store_line += line[:-1]
  781.             else:
  782.                 tmp = store_line + line
  783.                 self.append(tmp.strip())
  784.                 store_line = ""
  785.         if store_line:
  786.             raise Exception, "WRONG CARD FORMAT"
  787.        
  788.        
  789.     def move_to_last(self, cmd):
  790.         """move an element to the last history."""
  791.         for line in self[:]:
  792.             if line.startswith(cmd):
  793.                 self.remove(line)
  794.                 list.append(self, line)
  795.    
  796.     def append(self, line):
  797.         """"add a line in the proc_card perform automatically cleaning"""
  798.        
  799.         line = line.strip()
  800.         cmds = line.split()
  801.         if len(cmds) == 0:
  802.             return
  803.        
  804.         list.append(self, line)
  805.        
  806.         # command type:
  807.         cmd = cmds[0]
  808.        
  809.         if cmd == 'output':
  810.             # Remove previous outputs from history
  811.             self.clean(allow_for_removal = ['output'], keep_switch=True,
  812.                            remove_bef_last='output')
  813.         elif cmd == 'generate':
  814.             # Remove previous generations from history
  815.             self.clean(remove_bef_last='generate', keep_switch=True,
  816.                      allow_for_removal= ['generate', 'add process', 'output'])
  817.             self.info['generate'] = ' '.join(cmds[1:])
  818.         elif cmd == 'add' and cmds[1] == 'process' and not self.info['generate']:
  819.             self.info['generate'] = ' '.join(cmds[2:])
  820.         elif cmd == 'import':
  821.             if len(cmds) < 2:
  822.                 return
  823.             if cmds[1].startswith('model'):
  824.                 self.info['full_model_line'] = line
  825.                 self.clean(remove_bef_last='import', keep_switch=True,
  826.                         allow_for_removal=['generate', 'add process', 'add model', 'output'])
  827.                 if cmds[1] == 'model':
  828.                     self.info['model'] = cmds[2]
  829.                 else:
  830.                     self.info['model'] = None # not UFO model
  831.             elif cmds[1] == 'proc_v4':
  832.                 #full cleaning
  833.                 self[:] = []
  834.                
  835.  
  836.     def clean(self, to_keep=['set','add','load'],
  837.                             remove_bef_last=None,
  838.                             to_remove=['open','display','launch', 'check','history'],
  839.                             allow_for_removal=None,
  840.                             keep_switch=False):
  841.         """Remove command in arguments from history.
  842.        All command before the last occurrence of  'remove_bef_last'
  843.        (including it) will be removed (but if another options tells the opposite).                
  844.        'to_keep' is a set of line to always keep.
  845.        'to_remove' is a set of line to always remove (don't care about remove_bef_
  846.        status but keep_switch acts.).
  847.        if 'allow_for_removal' is define only the command in that list can be
  848.        remove of the history for older command that remove_bef_lb1. all parameter
  849.        present in to_remove are always remove even if they are not part of this
  850.        list.
  851.        keep_switch force to keep the statement remove_bef_??? which changes starts
  852.        the removal mode.
  853.        """
  854.  
  855.         #check consistency
  856.         if __debug__ and allow_for_removal:
  857.             for arg in to_keep:
  858.                 assert arg not in allow_for_removal
  859.            
  860.    
  861.         nline = -1
  862.         removal = False
  863.         #looping backward
  864.         while nline > -len(self):
  865.             switch  = False # set in True when removal pass in True
  866.  
  867.             #check if we need to pass in removal mode
  868.             if not removal and remove_bef_last:
  869.                     if self[nline].startswith(remove_bef_last):
  870.                         removal = True
  871.                         switch = True  
  872.  
  873.             # if this is the switch and is protected pass to the next element
  874.             if switch and keep_switch:
  875.                 nline -= 1
  876.                 continue
  877.  
  878.             # remove command in to_remove (whatever the status of removal)
  879.             if any([self[nline].startswith(arg) for arg in to_remove]):
  880.                 self.pop(nline)
  881.                 continue
  882.            
  883.             # Only if removal mode is active!
  884.             if removal:
  885.                 if allow_for_removal:
  886.                     # Only a subset of command can be removed
  887.                     if any([self[nline].startswith(arg)
  888.                                                  for arg in allow_for_removal]):
  889.                         self.pop(nline)
  890.                         continue
  891.                 elif not any([self[nline].startswith(arg) for arg in to_keep]):
  892.                     # All command have to be remove but protected
  893.                     self.pop(nline)
  894.                     continue
  895.            
  896.             # update the counter to pass to the next element
  897.             nline -= 1
  898.        
  899.     def get(self, tag, default=None):
  900.         if isinstance(tag, int):
  901.             list.__getattr__(self, tag)
  902.         elif tag == 'info' or tag == "__setstate__":
  903.             return default #for pickle
  904.         elif tag == "multiparticles":
  905.             out = []
  906.             for line in self:
  907.                 if line.startswith('define'):
  908.                     try:
  909.                         name, content = line[7:].split('=',1)
  910.                     except ValueError:
  911.                         name, content = line[7:].split(None,1)
  912.                     out.append((name, content))
  913.             return out
  914.         else:
  915.             return self.info[tag]
  916.            
  917.     def write(self, path):
  918.         """write the proc_card to a given path"""
  919.        
  920.         fsock = open(path, 'w')
  921.         fsock.write(self.history_header)
  922.         for line in self:
  923.             while len(line) > 70:
  924.                 sub, line = line[:70]+"\\" , line[70:]
  925.                 fsock.write(sub+"\n")
  926.             else:
  927.                 fsock.write(line+"\n")
  928.  
  929. class InvalidCardEdition(InvalidCmd): pass
  930.  
  931. class ConfigFile(dict):
  932.     """ a class for storing/dealing with input file.
  933.    """    
  934.  
  935.     def __init__(self, finput=None, **opt):
  936.         """initialize a new instance. input can be an instance of MadLoopParam,
  937.        a file, a path to a file, or simply Nothing"""                
  938.        
  939.         if isinstance(finput, self.__class__):
  940.             dict.__init__(self, finput)
  941.             assert finput.__dict__.keys()
  942.             for key in finput.__dict__:
  943.                 setattr(self, key, copy.copy(getattr(finput, key)) )
  944.             return
  945.         else:
  946.             dict.__init__(self)
  947.        
  948.         # Initialize it with all the default value
  949.         self.user_set = set()
  950.         self.auto_set = set()
  951.         self.system_only = set()
  952.         self.lower_to_case = {}
  953.         self.list_parameter = {} #key -> type of list (int/float/bool/str/...
  954.         self.dict_parameter = {}
  955.         self.comments = {} # comment associated to parameters. can be display via help message
  956.         # store the valid options for a given parameter.
  957.         self.allowed_value = {}
  958.        
  959.         self.default_setup()
  960.        
  961.  
  962.         # if input is define read that input
  963.         if isinstance(finput, (file, str, StringIO.StringIO)):
  964.             self.read(finput, **opt)
  965.  
  966.     def default_setup(self):
  967.         pass
  968.  
  969.     def __copy__(self):
  970.         return self.__class__(self)
  971.  
  972.     def __add__(self, other):
  973.         """define the sum"""
  974.         assert isinstance(other, dict)
  975.         base = self.__class__(self)
  976.         #base = copy.copy(self)
  977.         base.update((key.lower(),value) for key, value in other.items())
  978.         return base
  979.  
  980.     def __radd__(self, other):
  981.         """define the sum"""
  982.         new = copy.copy(other)
  983.         new.update((key, value) for key, value in self.items())
  984.         return new
  985.    
  986.     def __contains__(self, key):
  987.         return dict.__contains__(self, key.lower())
  988.  
  989.     def __iter__(self):
  990.         iter = super(ConfigFile, self).__iter__()
  991.         return (self.lower_to_case[name] for name in iter)
  992.    
  993.     def keys(self):
  994.         return [name for name in self]
  995.    
  996.     def items(self):
  997.         return [(name,self[name]) for name in self]
  998.        
  999.     @staticmethod
  1000.     def warn(text, level, raiseerror=False):
  1001.         """convenient proxy to raiseerror/print warning"""
  1002.  
  1003.         if raiseerror is True:
  1004.             raise InvalidCardEdition(text)
  1005.         elif raiseerror:
  1006.             raise raiseerror(text)
  1007.  
  1008.         if isinstance(level,str):
  1009.             log = getattr(logger, level.lower())
  1010.         elif isinstance(level, int):
  1011.             log = lambda t: logger.log(level, t)
  1012.         elif level:
  1013.             log = level
  1014.        
  1015.         return log(text)
  1016.  
  1017.     def post_set(self, name, value, change_userdefine, raiseerror):
  1018.        
  1019.         if value is None:
  1020.             value = self[name]
  1021.  
  1022.         if hasattr(self, 'post_set_%s' % name):
  1023.             return getattr(self, 'post_set_%s' % name)(value, change_userdefine, raiseerror)
  1024.    
  1025.     def __setitem__(self, name, value, change_userdefine=False,raiseerror=False):
  1026.         """set the attribute and set correctly the type if the value is a string.
  1027.           change_userdefine on True if we have to add the parameter in user_set
  1028.        """
  1029.                        
  1030.         if  not len(self):
  1031.             #Should never happen but when deepcopy/pickle
  1032.             self.__init__()
  1033.                
  1034.         name = name.strip()
  1035.         lower_name = name.lower()
  1036.  
  1037.         # 0. check if this parameter is a system only one
  1038.         if change_userdefine and lower_name in self.system_only:
  1039.             text='%s is a private entry which can not be modify by the user. Keep value at %s' % (name,self[name])
  1040.             self.warn(text, 'critical', raiseerror)
  1041.             return
  1042.        
  1043.         #1. check if the parameter is set to auto -> pass it to special
  1044.         if lower_name in self:
  1045.             targettype = type(dict.__getitem__(self, lower_name))
  1046.             if targettype != str and isinstance(value, str) and value.lower() == 'auto':
  1047.                 self.auto_set.add(lower_name)
  1048.                 if lower_name in self.user_set:
  1049.                     self.user_set.remove(lower_name)
  1050.                 #keep old value.
  1051.                 self.post_set(lower_name, 'auto', change_userdefine, raiseerror)
  1052.                 return
  1053.             elif lower_name in self.auto_set:
  1054.                 self.auto_set.remove(lower_name)
  1055.            
  1056.         # 2. Find the type of the attribute that we want
  1057.         if lower_name in self.list_parameter:
  1058.             targettype = self.list_parameter[lower_name]
  1059.            
  1060.            
  1061.            
  1062.             if isinstance(value, str):
  1063.                 # split for each comma/space
  1064.                 value = value.strip()
  1065.                 if value.startswith('[') and value.endswith(']'):
  1066.                     value = value[1:-1]
  1067.                 #do not perform split within a " or ' block  
  1068.                 data = re.split(r"((?<![\\])['\"])((?:.(?!(?<![\\])\1))*.?)\1", str(value))
  1069.                 new_value = []
  1070.                 i = 0
  1071.                 while len(data) > i:
  1072.                     current = filter(None, re.split(r'(?:(?<!\\)\s)|,', data[i]))
  1073.                     i+=1
  1074.                     if len(data) > i+1:
  1075.                         if current:
  1076.                             current[-1] += '{0}{1}{0}'.format(data[i], data[i+1])
  1077.                         else:
  1078.                             current = ['{0}{1}{0}'.format(data[i], data[i+1])]
  1079.                         i+=2
  1080.                     new_value += current
  1081.  
  1082.                 value = new_value                          
  1083.                
  1084.             elif not hasattr(value, '__iter__'):
  1085.                 value = [value]
  1086.             elif isinstance(value, dict):
  1087.                 text = "not being able to handle dictionary in card entry"
  1088.                 return self.warn(text, 'critical', raiseerror)
  1089.  
  1090.             #format each entry    
  1091.             values =[self.format_variable(v, targettype, name=name)
  1092.                                                                  for v in value]
  1093.            
  1094.             # ensure that each entry are in the allowed list
  1095.             if lower_name in self.allowed_value and '*' not in self.allowed_value[lower_name]:
  1096.                 new_values = []
  1097.                 dropped = []
  1098.                 for val in values:
  1099.                     allowed = self.allowed_value[lower_name]
  1100.            
  1101.                     if val in allowed:
  1102.                         new_values.append(val)
  1103.                         continue
  1104.                     elif isinstance(val, str):
  1105.                         val = val.lower()
  1106.                         allowed = allowed.lower()
  1107.                         if value in allowed:
  1108.                             i = allowed.index(value)
  1109.                             new_values.append(self.allowed_value[i])
  1110.                             continue
  1111.                     # no continue -> bad input
  1112.                     dropped.append(val)
  1113.                    
  1114.                 if not new_values:
  1115.  
  1116.                     text= "value '%s' for entry '%s' is not valid.  Preserving previous value: '%s'.\n" \
  1117.                                % (value, name, self[lower_name])
  1118.                     text += "allowed values are any list composed of the following entry: %s" % ', '.join([str(i) for i in self.allowed_value[lower_name]])
  1119.                     return self.warn(text, 'warning', raiseerror)                    
  1120.                 elif dropped:              
  1121.                     text = "some value for entry '%s' are not valid. Invalid item are: '%s'.\n" \
  1122.                                % (value, name, dropped)
  1123.                     text += "value will be set to %s" % new_values
  1124.                     text += "allowed items in the list are: %s" % ', '.join([str(i) for i in self.allowed_value[lower_name]])        
  1125.                     self.warn(text, 'warning')
  1126.  
  1127.                 values = new_values
  1128.  
  1129.             # make the assignment
  1130.             dict.__setitem__(self, lower_name, values)
  1131.             if change_userdefine:
  1132.                 self.user_set.add(lower_name)
  1133.             #check for specific action
  1134.             return self.post_set(lower_name, None, change_userdefine, raiseerror)
  1135.         elif lower_name in self.dict_parameter:
  1136.             targettype = self.dict_parameter[lower_name]
  1137.             full_reset = True #check if we just update the current dict or not
  1138.            
  1139.             if isinstance(value, str):
  1140.                 value = value.strip()
  1141.                 # allowed entry:
  1142.                 #   name : value   => just add the entry
  1143.                 #   name , value   => just add the entry
  1144.                 #   name  value    => just add the entry
  1145.                 #   {name1:value1, name2:value2}   => full reset
  1146.                
  1147.                 # split for each comma/space
  1148.                 if value.startswith('{') and value.endswith('}'):
  1149.                     new_value = {}
  1150.                     for pair in value[1:-1].split(','):
  1151.                         if not pair.strip():
  1152.                             break
  1153.                         x, y = pair.split(':')
  1154.                         x, y = x.strip(), y.strip()
  1155.                         if x.startswith(('"',"'")) and x.endswith(x[0]):
  1156.                             x = x[1:-1]
  1157.                         new_value[x] = y
  1158.                     value = new_value
  1159.                 elif ',' in value:
  1160.                     x,y = value.split(',')
  1161.                     value = {x.strip():y.strip()}
  1162.                     full_reset = False
  1163.                    
  1164.                 elif ':' in value:
  1165.                     x,y = value.split(':')
  1166.                     value = {x.strip():y.strip()}
  1167.                     full_reset = False      
  1168.                 else:
  1169.                     x,y = value.split()
  1170.                     value = {x:y}
  1171.                     full_reset = False
  1172.            
  1173.             if isinstance(value, dict):
  1174.                 for key in value:
  1175.                     value[key] = self.format_variable(value[key], targettype, name=name)
  1176.                 if full_reset:
  1177.                     dict.__setitem__(self, lower_name, value)
  1178.                 else:
  1179.                     dict.__getitem__(self, lower_name).update(value)
  1180.             else:
  1181.                 raise Exception, '%s should be of dict type'% lower_name
  1182.             if change_userdefine:
  1183.                 self.user_set.add(lower_name)
  1184.             return self.post_set(lower_name, None, change_userdefine, raiseerror)
  1185.         elif name in self:            
  1186.             targettype = type(self[name])
  1187.         else:
  1188.             logger.debug('Trying to add argument %s in %s. ' % (name, self.__class__.__name__) +\
  1189.               'This argument is not defined by default. Please consider adding it.')
  1190.             suggestions = [k for k in self.keys() if k.startswith(name[0].lower())]
  1191.             if len(suggestions)>0:
  1192.                 logger.debug("Did you mean one of the following: %s"%suggestions)
  1193.             self.add_param(lower_name, self.format_variable(UnknownType(value),
  1194.                                                              UnknownType, name))
  1195.             self.lower_to_case[lower_name] = name
  1196.             if change_userdefine:
  1197.                 self.user_set.add(lower_name)
  1198.             return self.post_set(lower_name, None, change_userdefine, raiseerror)
  1199.    
  1200.         value = self.format_variable(value, targettype, name=name)
  1201.         #check that the value is allowed:
  1202.         if lower_name in self.allowed_value and '*' not in self.allowed_value[lower_name]:
  1203.             valid = False
  1204.             allowed = self.allowed_value[lower_name]
  1205.            
  1206.             # check if the current value is allowed or not (set valid to True)
  1207.             if value in allowed:
  1208.                 valid=True    
  1209.             elif isinstance(value, str):
  1210.                 value = value.lower()
  1211.                 allowed = [v.lower() for v in allowed]
  1212.                 if value in allowed:
  1213.                     i = allowed.index(value)
  1214.                     value = self.allowed_value[lower_name][i]
  1215.                     valid=True
  1216.                    
  1217.             if not valid:
  1218.                 # act if not valid:
  1219.                 text = "value '%s' for entry '%s' is not valid.  Preserving previous value: '%s'.\n" \
  1220.                                % (value, name, self[lower_name])
  1221.                 text += "allowed values are %s\n" % ', '.join([str(i) for i in self.allowed_value[lower_name]])
  1222.                 if lower_name in self.comments:
  1223.                     text += 'type "help %s" for more information' % name
  1224.                 return self.warn(text, 'warning', raiseerror)
  1225.  
  1226.         dict.__setitem__(self, lower_name, value)
  1227.         if change_userdefine:
  1228.             self.user_set.add(lower_name)
  1229.         self.post_set(lower_name, None, change_userdefine, raiseerror)
  1230.  
  1231.  
  1232.     def add_param(self, name, value, system=False, comment=False, typelist=None,
  1233.                   allowed=[]):
  1234.         """add a default parameter to the class"""
  1235.  
  1236.         lower_name = name.lower()
  1237.         if __debug__:
  1238.             if lower_name in self:
  1239.                 raise Exception("Duplicate case for %s in %s" % (name,self.__class__))
  1240.            
  1241.         dict.__setitem__(self, lower_name, value)
  1242.         self.lower_to_case[lower_name] = name
  1243.         if isinstance(value, list):
  1244.             if len(value):
  1245.                 targettype = type(value[0])
  1246.             else:
  1247.                 targettype=typelist
  1248.                 assert typelist
  1249.             if any([targettype != type(v) for v in value]):
  1250.                 raise Exception, "All entry should have the same type"
  1251.             self.list_parameter[lower_name] = targettype
  1252.         elif isinstance(value, dict):
  1253.             allvalues = value.values()
  1254.             if any([type(allvalues[0]) != type(v) for v in allvalues]):
  1255.                 raise Exception, "All entry should have the same type"  
  1256.             self.dict_parameter[lower_name] = type(allvalues[0])  
  1257.             if '__type__' in value:
  1258.                 del value['__type__']
  1259.                 dict.__setitem__(self, lower_name, value)
  1260.        
  1261.         if allowed and allowed != ['*']:
  1262.             self.allowed_value[lower_name] = allowed
  1263.             assert value in allowed or '*' in allowed
  1264.         #elif isinstance(value, bool) and allowed != ['*']:
  1265.         #    self.allowed_value[name] = [True, False]
  1266.                    
  1267.         if system:
  1268.             self.system_only.add(lower_name)
  1269.         if comment:
  1270.             self.comments[lower_name] = comment
  1271.  
  1272.     def do_help(self, name):
  1273.         """return a minimal help for the parameter"""
  1274.        
  1275.         out = "## Information on parameter %s from class %s\n" % (name, self.__class__.__name__)
  1276.         if name.lower() in self:
  1277.             out += "## current value: %s (parameter should be of type %s)\n" % (self[name], type(self[name]))
  1278.             if name.lower() in self.comments:
  1279.                 out += '## %s\n' % self.comments[name.lower()].replace('\n', '\n## ')
  1280.         else:
  1281.             out += "## Unknown for this class\n"
  1282.         if name.lower() in self.user_set:
  1283.             out += "## This value is considered as been set by the user\n"
  1284.         else:
  1285.             out += "## This value is considered as been set by the system\n"
  1286.         if name.lower() in self.allowed_value:
  1287.             if '*' not in self.allowed_value[name.lower()]:
  1288.                 out += "Allowed value are: %s\n" % ','.join([str(p) for p in self.allowed_value[name.lower()]])
  1289.             else:
  1290.                 out += "Suggested value are : %s\n " % ','.join([str(p) for p in self.allowed_value[name.lower()] if p!='*'])
  1291.        
  1292.         logger.info(out)
  1293.         return out
  1294.  
  1295.     @staticmethod
  1296.     def format_variable(value, targettype, name="unknown"):
  1297.         """assign the value to the attribute for the given format"""
  1298.        
  1299.         if not isinstance(value, str):
  1300.             # just have to check that we have the correct format
  1301.             if isinstance(value, targettype):
  1302.                 pass # assignement at the end
  1303.             elif isinstance(value, numbers.Number) and issubclass(targettype, numbers.Number):
  1304.                 try:
  1305.                     new_value = targettype(value)
  1306.                 except TypeError:
  1307.                     if value.imag/value.real<1e-12:
  1308.                         new_value = targettype(value.real)
  1309.                     else:
  1310.                         raise
  1311.                 if new_value == value:
  1312.                     value = new_value
  1313.                 else:
  1314.                     raise InvalidCmd, "Wrong input type for %s found %s and expecting %s for value %s" %\
  1315.                         (name, type(value), targettype, value)
  1316.             else:
  1317.                 raise InvalidCmd, "Wrong input type for %s found %s and expecting %s for value %s" %\
  1318.                         (name, type(value), targettype, value)                
  1319.         else:
  1320.             # We have a string we have to format the attribute from the string
  1321.             if targettype == UnknownType:
  1322.                 # No formatting
  1323.                 pass
  1324.             elif targettype == bool:
  1325.                 value = value.strip()
  1326.                 if value.lower() in ['0', '.false.', 'f', 'false', 'off']:
  1327.                     value = False
  1328.                 elif value.lower() in ['1', '.true.', 't', 'true', 'on']:
  1329.                     value = True
  1330.                 else:
  1331.                     raise InvalidCmd, "%s can not be mapped to True/False for %s" % (repr(value),name)
  1332.             elif targettype == str:
  1333.                 value = value.strip()
  1334.                 if value.startswith('\'') and value.endswith('\''):
  1335.                     value = value[1:-1]
  1336.                 elif value.startswith('"') and value.endswith('"'):
  1337.                     value = value[1:-1]
  1338.             elif targettype == int:
  1339.                 if value.isdigit():
  1340.                     value = int(value)
  1341.                 elif value[1:].isdigit() and value[0] == '-':
  1342.                     value = int(value)
  1343.                 elif value.endswith(('k', 'M')) and value[:-1].isdigit():
  1344.                     convert = {'k':1000, 'M':1000000}
  1345.                     value =int(value[:-1]) * convert[value[-1]]
  1346.                 else:
  1347.                     try:
  1348.                         value = float(value.replace('d','e'))
  1349.                     except ValueError:
  1350.                         raise InvalidCmd, "%s can not be mapped to an integer" % value                    
  1351.                     try:
  1352.                         new_value = int(value)
  1353.                     except ValueError:
  1354.                         raise InvalidCmd, "%s can not be mapped to an integer" % value
  1355.                     else:
  1356.                         if value == new_value:
  1357.                             value = new_value
  1358.                         else:
  1359.                             raise InvalidCmd, "incorect input: %s need an integer for %s" % (value,name)
  1360.             elif targettype == float:
  1361.                 value = value.replace('d','e') # pass from Fortran formatting
  1362.                 try:
  1363.                     value = float(value)
  1364.                 except ValueError:
  1365.                     try:
  1366.                         split = re.split('(\*|/)',value)
  1367.                         v = float(split[0])
  1368.                         for i in range((len(split)//2)):
  1369.                             if split[2*i+1] == '*':
  1370.                                 v *=  float(split[2*i+2])
  1371.                             else:
  1372.                                 v /=  float(split[2*i+2])
  1373.                     except:
  1374.                         v=0
  1375.                         raise InvalidCmd, "%s can not be mapped to a float" % value
  1376.                     finally:
  1377.                         value = v
  1378.             else:
  1379.                 raise InvalidCmd, "type %s is not handle by the card" % targettype
  1380.            
  1381.         return value
  1382.            
  1383.  
  1384.  
  1385.     def __getitem__(self, name):
  1386.        
  1387.         lower_name = name.lower()
  1388.         if __debug__:
  1389.             if lower_name not in self:
  1390.                 if lower_name in [key.lower() for key in self] :
  1391.                     raise Exception, "Some key are not lower case %s. Invalid use of the class!"\
  1392.                                      % [key for key in self if key.lower() != key]
  1393.        
  1394.         if lower_name in self.auto_set:
  1395.             return 'auto'
  1396.  
  1397.         return dict.__getitem__(self, name.lower())
  1398.  
  1399.    
  1400.     def set(self, name, value, changeifuserset=True, user=False, raiseerror=False):
  1401.         """convenient way to change attribute.
  1402.        changeifuserset=False means that the value is NOT change is the value is not on default.
  1403.        user=True, means that the value will be marked as modified by the user
  1404.        (potentially preventing future change to the value)
  1405.        """
  1406.  
  1407.         # changeifuserset=False -> we need to check if the user force a value.
  1408.         if not changeifuserset:
  1409.             if name.lower() in self.user_set:
  1410.                 #value modified by the user -> do nothing
  1411.                 return
  1412.            
  1413.         self.__setitem__(name, value, change_userdefine=user, raiseerror=raiseerror)
  1414.  
  1415.  
  1416.  
  1417. class ProcCharacteristic(ConfigFile):
  1418.     """A class to handle information which are passed from MadGraph to the madevent
  1419.       interface."""
  1420.      
  1421.     def default_setup(self):
  1422.         """initialize the directory to the default value"""
  1423.        
  1424.         self.add_param('loop_induced', False)
  1425.         self.add_param('has_isr', False)
  1426.         self.add_param('has_fsr', False)
  1427.         self.add_param('nb_channel', 0)
  1428.         self.add_param('nexternal', 0)
  1429.         self.add_param('ninitial', 0)
  1430.         self.add_param('grouped_matrix', True)
  1431.         self.add_param('has_loops', False)
  1432.         self.add_param('bias_module','None')
  1433.         self.add_param('max_n_matched_jets', 0)
  1434.         self.add_param('colored_pdgs', [1,2,3,4,5])
  1435.         self.add_param('complex_mass_scheme', False)
  1436.         self.add_param('pdg_initial1', [0])
  1437.         self.add_param('pdg_initial2', [0])        
  1438.  
  1439.     def read(self, finput):
  1440.         """Read the input file, this can be a path to a file,
  1441.           a file object, a str with the content of the file."""
  1442.            
  1443.         if isinstance(finput, str):
  1444.             if "\n" in finput:
  1445.                 finput = finput.split('\n')
  1446.             elif os.path.isfile(finput):
  1447.                 finput = open(finput)
  1448.             else:
  1449.                 raise Exception, "No such file %s" % finput
  1450.            
  1451.         for line in finput:
  1452.             if '#' in line:
  1453.                 line = line.split('#',1)[0]
  1454.             if not line:
  1455.                 continue
  1456.            
  1457.             if '=' in line:
  1458.                 key, value = line.split('=',1)
  1459.                 self[key.strip()] = value
  1460.          
  1461.     def write(self, outputpath):
  1462.         """write the file"""
  1463.  
  1464.         template ="#    Information about the process      #\n"
  1465.         template +="#########################################\n"
  1466.        
  1467.         fsock = open(outputpath, 'w')
  1468.         fsock.write(template)
  1469.        
  1470.         for key, value in self.items():
  1471.             fsock.write(" %s = %s \n" % (key, value))
  1472.        
  1473.         fsock.close()  
  1474.  
  1475.  
  1476.  
  1477.  
  1478. class GridpackCard(ConfigFile):
  1479.     """an object for the GridpackCard"""
  1480.    
  1481.     def default_setup(self):
  1482.         """default value for the GridpackCard"""
  1483.    
  1484.         self.add_param("GridRun", True)
  1485.         self.add_param("gevents", 2500)
  1486.         self.add_param("gseed", 1)
  1487.         self.add_param("ngran", -1)  
  1488.  
  1489.     def read(self, finput):
  1490.         """Read the input file, this can be a path to a file,
  1491.           a file object, a str with the content of the file."""
  1492.            
  1493.         if isinstance(finput, str):
  1494.             if "\n" in finput:
  1495.                 finput = finput.split('\n')
  1496.             elif os.path.isfile(finput):
  1497.                 finput = open(finput)
  1498.             else:
  1499.                 raise Exception, "No such file %s" % finput
  1500.        
  1501.         for line in finput:
  1502.             line = line.split('#')[0]
  1503.             line = line.split('!')[0]
  1504.             line = line.split('=',1)
  1505.             if len(line) != 2:
  1506.                 continue
  1507.             self[line[1].strip()] = line[0].replace('\'','').strip()
  1508.  
  1509.     def write(self, output_file, template=None):
  1510.         """Write the run_card in output_file according to template
  1511.           (a path to a valid run_card)"""
  1512.  
  1513.         if not template:
  1514.             if not MADEVENT:
  1515.                 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
  1516.                                                         'grid_card_default.dat')
  1517.             else:
  1518.                 template = pjoin(MEDIR, 'Cards', 'grid_card_default.dat')
  1519.  
  1520.                
  1521.         text = ""
  1522.         for line in file(template,'r'):                  
  1523.             nline = line.split('#')[0]
  1524.             nline = nline.split('!')[0]
  1525.             comment = line[len(nline):]
  1526.             nline = nline.split('=')
  1527.             if len(nline) != 2:
  1528.                 text += line
  1529.             elif nline[1].strip() in self:
  1530.                 text += '  %s\t= %s %s' % (self[nline[1].strip()],nline[1], comment)        
  1531.             else:
  1532.                 logger.info('Adding missing parameter %s to current run_card (with default value)' % nline[1].strip())
  1533.                 text += line
  1534.        
  1535.         if isinstance(output_file, str):
  1536.             fsock =  open(output_file,'w')
  1537.         else:
  1538.             fsock = output_file
  1539.            
  1540.         fsock.write(text)
  1541.         fsock.close()
  1542.        
  1543. class PY8Card(ConfigFile):
  1544.     """ Implements the Pythia8 card."""
  1545.  
  1546.     def add_default_subruns(self, type):
  1547.         """ Placeholder function to allow overwriting in the PY8SubRun daughter.
  1548.        The initialization of the self.subruns attribute should of course not
  1549.        be performed in PY8SubRun."""
  1550.         if type == 'parameters':
  1551.             if "LHEFInputs:nSubruns" not in self:
  1552.                 self.add_param("LHEFInputs:nSubruns", 1,
  1553.                 hidden='ALWAYS_WRITTEN',
  1554.                 comment="""
  1555.    ====================
  1556.    Subrun definitions
  1557.    ====================
  1558.    """)
  1559.         if type == 'attributes':
  1560.             if not(hasattr(self,'subruns')):
  1561.                 first_subrun = PY8SubRun(subrun_id=0)
  1562.                 self.subruns = dict([(first_subrun['Main:subrun'],first_subrun)])
  1563.  
  1564.     def default_setup(self):
  1565.         """ Sets up the list of available PY8 parameters."""
  1566.        
  1567.         # Visible parameters
  1568.         # ==================
  1569.         self.add_param("Main:numberOfEvents", -1)
  1570.         # for MLM merging
  1571.         # -1.0 means that it will be set automatically by MadGraph5_aMC@NLO
  1572.         self.add_param("JetMatching:qCut", -1.0, always_write_to_card=False)
  1573.         self.add_param("JetMatching:doShowerKt",False,always_write_to_card=False)
  1574.         # -1 means that it is automatically set.
  1575.         self.add_param("JetMatching:nJetMax", -1, always_write_to_card=False)
  1576.         # for CKKWL merging
  1577.         self.add_param("Merging:TMS", -1.0, always_write_to_card=False)
  1578.         self.add_param("Merging:Process", '<set_by_user>', always_write_to_card=False)
  1579.         # -1 means that it is automatically set.  
  1580.         self.add_param("Merging:nJetMax", -1, always_write_to_card=False)
  1581.         # for both merging, chose whether to also consider different merging
  1582.         # scale values for the extra weights related to scale and PDF variations.
  1583.         self.add_param("SysCalc:fullCutVariation", False)
  1584.         # Select the HepMC output. The user can prepend 'fifo:<optional_fifo_path>'
  1585.         # to indicate that he wants to pipe the output. Or /dev/null to turn the
  1586.         # output off.
  1587.         self.add_param("HEPMCoutput:file", 'auto')
  1588.  
  1589.         # Hidden parameters always written out
  1590.         # ====================================
  1591.         self.add_param("Beams:frameType", 4,
  1592.             hidden=True,
  1593.             comment='Tell Pythia8 that an LHEF input is used.')
  1594.         self.add_param("HEPMCoutput:scaling", 1.0e9,
  1595.             hidden=True,
  1596.             comment='1.0 corresponds to HEPMC weight given in [mb]. We choose here the [pb] normalization.')
  1597.         self.add_param("Check:epTolErr", 1e-2,
  1598.             hidden=True,
  1599.             comment='Be more forgiving with momentum mismatches.')
  1600.         # By default it is important to disable any cut on the rapidity of the showered jets
  1601.         # during MLML merging and by default it is set to 2.5
  1602.         self.add_param("JetMatching:etaJetMax", 1000.0, hidden=True, always_write_to_card=True)
  1603.  
  1604.         # Hidden parameters written out only if user_set or system_set
  1605.         # ============================================================
  1606.         self.add_param("PDF:pSet", 'LHAPDF5:CT10.LHgrid', hidden=True, always_write_to_card=False,
  1607.             comment='Reminder: Parameter below is shower tune dependent.')
  1608.         self.add_param("SpaceShower:alphaSvalue", 0.118, hidden=True, always_write_to_card=False,
  1609.             comment='Reminder: Parameter below is shower tune dependent.')
  1610.         self.add_param("TimeShower:alphaSvalue", 0.118, hidden=True, always_write_to_card=False,
  1611.             comment='Reminder: Parameter below is shower tune dependent.')
  1612.         self.add_param("hadronlevel:all", True, hidden=True, always_write_to_card=False,
  1613.             comment='This allows to turn on/off hadronization alltogether.')
  1614.         self.add_param("partonlevel:mpi", True, hidden=True, always_write_to_card=False,
  1615.             comment='This allows to turn on/off MPI alltogether.')
  1616.         self.add_param("Beams:setProductionScalesFromLHEF", False, hidden=True,
  1617.             always_write_to_card=False,
  1618.             comment='This parameter is automatically set to True by MG5aMC when doing MLM merging with PY8.')
  1619.        
  1620.         # for MLM merging
  1621.         self.add_param("JetMatching:merge", False, hidden=True, always_write_to_card=False,
  1622.           comment='Specifiy if we are merging sample of different multiplicity.')
  1623.         self.add_param("SysCalc:qCutList", [10.0,20.0], hidden=True, always_write_to_card=False)
  1624.         self['SysCalc:qCutList'] = 'auto'
  1625.         self.add_param("SysCalc:qWeed",-1.0,hidden=True, always_write_to_card=False,
  1626.           comment='Value of the merging scale below which one does not even write the HepMC event.')
  1627.         self.add_param("JetMatching:doVeto", False, hidden=True, always_write_to_card=False,
  1628.           comment='Do veto externally (e.g. in SysCalc).')
  1629.         self.add_param("JetMatching:scheme", 1, hidden=True, always_write_to_card=False)
  1630.         self.add_param("JetMatching:setMad", False, hidden=True, always_write_to_card=False,
  1631.               comment='Specify one must read inputs from the MadGraph banner.')
  1632.         self.add_param("JetMatching:coneRadius", 1.0, hidden=True, always_write_to_card=False)
  1633.         self.add_param("JetMatching:nQmatch",4,hidden=True, always_write_to_card=False)
  1634.         # for CKKWL merging (common with UMEPS, UNLOPS)
  1635.         self.add_param("TimeShower:pTmaxMatch", 2, hidden=True, always_write_to_card=False)
  1636.         self.add_param("SpaceShower:pTmaxMatch", 1, hidden=True, always_write_to_card=False)
  1637.         self.add_param("SysCalc:tmsList", [10.0,20.0], hidden=True, always_write_to_card=False)
  1638.         self['SysCalc:tmsList'] = 'auto'
  1639.         self.add_param("Merging:muFac", 91.188, hidden=True, always_write_to_card=False,
  1640.                         comment='Set factorisation scales of the 2->2 process.')
  1641.         self.add_param("Merging:applyVeto", False, hidden=True, always_write_to_card=False,
  1642.           comment='Do veto externally (e.g. in SysCalc).')
  1643.         self.add_param("Merging:includeWeightInXsection", True, hidden=True, always_write_to_card=False,
  1644.           comment='If turned off, then the option belows forces PY8 to keep the original weight.')                      
  1645.         self.add_param("Merging:muRen", 91.188, hidden=True, always_write_to_card=False,
  1646.                       comment='Set renormalization scales of the 2->2 process.')
  1647.         self.add_param("Merging:muFacInME", 91.188, hidden=True, always_write_to_card=False,
  1648.                  comment='Set factorisation scales of the 2->2 Matrix Element.')
  1649.         self.add_param("Merging:muRenInME", 91.188, hidden=True, always_write_to_card=False,
  1650.                comment='Set renormalization scales of the 2->2 Matrix Element.')
  1651.         self.add_param("SpaceShower:rapidityOrder", False, hidden=True, always_write_to_card=False)
  1652.         self.add_param("Merging:nQuarksMerge",4,hidden=True, always_write_to_card=False)
  1653.         # To be added in subruns for CKKWL
  1654.         self.add_param("Merging:mayRemoveDecayProducts", False, hidden=True, always_write_to_card=False)
  1655.         self.add_param("Merging:doKTMerging", False, hidden=True, always_write_to_card=False)
  1656.         self.add_param("Merging:Dparameter", 0.4, hidden=True, always_write_to_card=False)        
  1657.         self.add_param("Merging:doPTLundMerging", False, hidden=True, always_write_to_card=False)
  1658.  
  1659.         # Special Pythia8 paremeters useful to simplify the shower.
  1660.         self.add_param("BeamRemnants:primordialKT", True, hidden=True, always_write_to_card=False, comment="see http://home.thep.lu.se/~torbjorn/pythia82html/BeamRemnants.html")
  1661.         self.add_param("PartonLevel:Remnants", True, hidden=True, always_write_to_card=False, comment="Master switch for addition of beam remnants. Cannot be used to generate complete events")
  1662.         self.add_param("Check:event", True, hidden=True, always_write_to_card=False, comment="check physical sanity of the events")
  1663.         self.add_param("TimeShower:QEDshowerByQ", True, hidden=True, always_write_to_card=False, comment="Allow quarks to radiate photons for FSR, i.e. branchings q -> q gamma")
  1664.         self.add_param("TimeShower:QEDshowerByL", True, hidden=True, always_write_to_card=False, comment="Allow leptons to radiate photons for FSR, i.e. branchings l -> l gamma")
  1665.         self.add_param("SpaceShower:QEDshowerByQ", True, hidden=True, always_write_to_card=False, comment="Allow quarks to radiate photons for ISR, i.e. branchings q -> q gamma")
  1666.         self.add_param("SpaceShower:QEDshowerByL", True, hidden=True, always_write_to_card=False, comment="Allow leptons to radiate photonsfor ISR, i.e. branchings l -> l gamma")
  1667.         self.add_param("PartonLevel:FSRinResonances", True, hidden=True, always_write_to_card=False, comment="Do not allow shower to run from decay product of unstable particle")
  1668.         self.add_param("ProcessLevel:resonanceDecays", True, hidden=True, always_write_to_card=False, comment="Do not allow unstable particle to decay.")
  1669.  
  1670.         # Add parameters controlling the subruns execution flow.
  1671.         # These parameters should not be part of PY8SubRun daughter.
  1672.         self.add_default_subruns('parameters')
  1673.              
  1674.     def __init__(self, *args, **opts):
  1675.         # Parameters which are not printed in the card unless they are
  1676.         # 'user_set' or 'system_set' or part of the
  1677.         #  self.hidden_params_to_always_print set.
  1678.         self.hidden_param = []
  1679.         self.hidden_params_to_always_write = set()
  1680.         self.visible_params_to_always_write = set()
  1681.         # List of parameters that should never be written out given the current context.
  1682.         self.params_to_never_write = set()
  1683.        
  1684.         # Parameters which have been set by the system (i.e. MG5 itself during
  1685.         # the regular course of the shower interface)
  1686.         self.system_set = set()
  1687.        
  1688.         # Add attributes controlling the subruns execution flow.
  1689.         # These attributes should not be part of PY8SubRun daughter.
  1690.         self.add_default_subruns('attributes')
  1691.        
  1692.         # Parameters which have been set by the
  1693.         super(PY8Card, self).__init__(*args, **opts)
  1694.  
  1695.     def add_param(self, name, value, hidden=False, always_write_to_card=True,
  1696.                                                                   comment=None):
  1697.         """ add a parameter to the card. value is the default value and
  1698.        defines the type (int/float/bool/str) of the input.
  1699.        The option 'hidden' decides whether the parameter should be visible to the user.
  1700.        The option 'always_write_to_card' decides whether it should
  1701.        always be printed or only when it is system_set or user_set.
  1702.        The option 'comment' can be used to specify a comment to write above
  1703.        hidden parameters.
  1704.        """
  1705.         super(PY8Card, self).add_param(name, value, comment=comment)
  1706.         name = name.lower()
  1707.         if hidden:
  1708.             self.hidden_param.append(name)
  1709.             if always_write_to_card:
  1710.                 self.hidden_params_to_always_write.add(name)
  1711.         else:
  1712.             if always_write_to_card:
  1713.                 self.visible_params_to_always_write.add(name)                
  1714.         if not comment is None:
  1715.             if not isinstance(comment, str):
  1716.                 raise MadGraph5Error("Option 'comment' must be a string, not"+\
  1717.                                                           " '%s'."%str(comment))
  1718.  
  1719.     def add_subrun(self, py8_subrun):
  1720.         """Add a subrun to this PY8 Card."""
  1721.         assert(isinstance(py8_subrun,PY8SubRun))
  1722.         if py8_subrun['Main:subrun']==-1:
  1723.             raise MadGraph5Error, "Make sure to correctly set the subrun ID"+\
  1724.                             " 'Main:subrun' *before* adding it to the PY8 Card."
  1725.         if py8_subrun['Main:subrun'] in self.subruns:
  1726.             raise MadGraph5Error, "A subrun with ID '%s'"%py8_subrun['Main:subrun']+\
  1727.                 " is already present in this PY8 card. Remove it first, or "+\
  1728.                                                           " access it directly."
  1729.         self.subruns[py8_subrun['Main:subrun']] = py8_subrun
  1730.         if not 'LHEFInputs:nSubruns' in self.user_set:
  1731.             self['LHEFInputs:nSubruns'] = max(self.subruns.keys())
  1732.        
  1733.     def userSet(self, name, value, **opts):
  1734.         """Set an attribute of this card, following a user_request"""
  1735.         self.__setitem__(name, value, change_userdefine=True, **opts)
  1736.         if name.lower() in self.system_set:
  1737.             self.system_set.remove(name.lower())
  1738.  
  1739.     def vetoParamWriteOut(self, name):
  1740.         """ Forbid the writeout of a specific parameter of this card when the
  1741.        "write" function will be invoked."""
  1742.         self.params_to_never_write.add(name.lower())
  1743.    
  1744.     def systemSet(self, name, value, **opts):
  1745.         """Set an attribute of this card, independently of a specific user
  1746.        request and only if not already user_set."""
  1747.         try:
  1748.             force = opts.pop('force')
  1749.         except KeyError:
  1750.             force = False
  1751.         if force or name.lower() not in self.user_set:
  1752.             self.__setitem__(name, value, change_userdefine=False, **opts)
  1753.             self.system_set.add(name.lower())
  1754.    
  1755.     def MadGraphSet(self, name, value, **opts):
  1756.         """ Sets a card attribute, but only if it is absent or not already
  1757.        user_set."""
  1758.         try:
  1759.             force = opts.pop('force')
  1760.         except KeyError:
  1761.             force = False
  1762.         if name.lower() not in self or (force or name.lower() not in self.user_set):
  1763.             self.__setitem__(name, value, change_userdefine=False, **opts)
  1764.             self.system_set.add(name.lower())            
  1765.    
  1766.     def defaultSet(self, name, value, **opts):
  1767.             self.__setitem__(name, value, change_userdefine=False, **opts)
  1768.        
  1769.     @staticmethod
  1770.     def pythia8_formatting(value, formatv=None):
  1771.         """format the variable into pythia8 card convention.
  1772.        The type is detected by default"""
  1773.         if not formatv:
  1774.             if isinstance(value,UnknownType):
  1775.                 formatv = 'unknown'                
  1776.             elif isinstance(value, bool):
  1777.                 formatv = 'bool'
  1778.             elif isinstance(value, int):
  1779.                 formatv = 'int'
  1780.             elif isinstance(value, float):
  1781.                 formatv = 'float'
  1782.             elif isinstance(value, str):
  1783.                 formatv = 'str'
  1784.             elif isinstance(value, list):
  1785.                 formatv = 'list'
  1786.             else:
  1787.                 logger.debug("unknow format for pythia8_formatting: %s" , value)
  1788.                 formatv = 'str'
  1789.         else:
  1790.             assert formatv
  1791.            
  1792.         if formatv == 'unknown':
  1793.             # No formatting then
  1794.             return str(value)
  1795.         if formatv == 'bool':
  1796.             if str(value) in ['1','T','.true.','True','on']:
  1797.                 return 'on'
  1798.             else:
  1799.                 return 'off'
  1800.         elif formatv == 'int':
  1801.             try:
  1802.                 return str(int(value))
  1803.             except ValueError:
  1804.                 fl = float(value)
  1805.                 if int(fl) == fl:
  1806.                     return str(int(fl))
  1807.                 else:
  1808.                     raise
  1809.         elif formatv == 'float':
  1810.             return '%.10e' % float(value)
  1811.         elif formatv == 'shortfloat':
  1812.             return '%.3f' % float(value)        
  1813.         elif formatv == 'str':
  1814.             return "%s" % value
  1815.         elif formatv == 'list':
  1816.             if len(value) and isinstance(value[0],float):
  1817.                 return ','.join([PY8Card.pythia8_formatting(arg, 'shortfloat') for arg in value])
  1818.             else:
  1819.                 return ','.join([PY8Card.pythia8_formatting(arg) for arg in value])
  1820.            
  1821.  
  1822.     def write(self, output_file, template, read_subrun=False,
  1823.                     print_only_visible=False, direct_pythia_input=False, add_missing=True):
  1824.         """ Write the card to output_file using a specific template.
  1825.        > 'print_only_visible' specifies whether or not the hidden parameters
  1826.            should be written out if they are in the hidden_params_to_always_write
  1827.            list and system_set.
  1828.        > If 'direct_pythia_input' is true, then visible parameters which are not
  1829.          in the self.visible_params_to_always_write list and are not user_set
  1830.          or system_set are commented.
  1831.        > If 'add_missing' is False then parameters that should be written_out but are absent
  1832.        from the template will not be written out."""
  1833.  
  1834.         # First list the visible parameters
  1835.         visible_param = [p for p in self if p.lower() not in self.hidden_param
  1836.                                                   or p.lower() in self.user_set]
  1837.         # Filter against list of parameters vetoed for write-out
  1838.         visible_param = [p for p in visible_param if p.lower() not in self.params_to_never_write]
  1839.        
  1840.         # Now the hidden param which must be written out
  1841.         if print_only_visible:
  1842.             hidden_output_param = []
  1843.         else:
  1844.             hidden_output_param = [p for p in self if p.lower() in self.hidden_param and
  1845.               not p.lower() in self.user_set and
  1846.               (p.lower() in self.hidden_params_to_always_write or
  1847.                                                   p.lower() in self.system_set)]
  1848.         # Filter against list of parameters vetoed for write-out
  1849.         hidden_output_param = [p for p in hidden_output_param if p not in self.params_to_never_write]
  1850.        
  1851.         if print_only_visible:
  1852.             subruns = []
  1853.         else:
  1854.             if not read_subrun:
  1855.                 subruns = sorted(self.subruns.keys())
  1856.        
  1857.         # Store the subruns to write in a dictionary, with its ID in key
  1858.         # and the corresponding stringstream in value
  1859.         subruns_to_write = {}
  1860.        
  1861.         # Sort these parameters nicely so as to put together parameters
  1862.         # belonging to the same group (i.e. prefix before the ':' in their name).
  1863.         def group_params(params):
  1864.             if len(params)==0:
  1865.                 return []
  1866.             groups = {}
  1867.             for p in params:
  1868.                 try:
  1869.                     groups[':'.join(p.split(':')[:-1])].append(p)
  1870.                 except KeyError:
  1871.                     groups[':'.join(p.split(':')[:-1])] = [p,]
  1872.             res =  sum(groups.values(),[])
  1873.             # Make sure 'Main:subrun' appears first
  1874.             if 'Main:subrun' in res:
  1875.                 res.insert(0,res.pop(res.index('Main:subrun')))
  1876.             # Make sure 'LHEFInputs:nSubruns' appears last
  1877.             if 'LHEFInputs:nSubruns' in res:
  1878.                 res.append(res.pop(res.index('LHEFInputs:nSubruns')))
  1879.             return res
  1880.  
  1881.         visible_param       = group_params(visible_param)
  1882.         hidden_output_param = group_params(hidden_output_param)
  1883.  
  1884.         # First dump in a temporary_output (might need to have a second pass
  1885.         # at the very end to update 'LHEFInputs:nSubruns')
  1886.         output = StringIO.StringIO()
  1887.            
  1888.         # Setup template from which to read
  1889.         if isinstance(template, str):
  1890.             if os.path.isfile(template):
  1891.                 tmpl = open(template, 'r')
  1892.             elif '\n' in template:
  1893.                 tmpl = StringIO.StringIO(template)
  1894.             else:
  1895.                 raise Exception, "File input '%s' not found." % file_input    
  1896.         elif template is None:
  1897.             # Then use a dummy empty StringIO, hence skipping the reading
  1898.             tmpl = StringIO.StringIO()
  1899.         elif isinstance(template, (StringIO.StringIO, file)):
  1900.             tmpl = template
  1901.         else:
  1902.             raise MadGraph5Error("Incorrect type for argument 'template': %s"%
  1903.                                                     template.__class__.__name__)
  1904.  
  1905.         # Read the template
  1906.         last_pos = tmpl.tell()
  1907.         line     = tmpl.readline()
  1908.         started_subrun_reading = False
  1909.         while line!='':
  1910.             # Skip comments
  1911.             if line.strip().startswith('!') or \
  1912.                line.strip().startswith('\n') or\
  1913.                line.strip() == '':
  1914.                 output.write(line)
  1915.                 # Proceed to next line
  1916.                 last_pos = tmpl.tell()
  1917.                 line     = tmpl.readline()
  1918.                 continue
  1919.             # Read parameter
  1920.             try:
  1921.                 param_entry, value_entry = line.split('=')
  1922.                 param = param_entry.strip()
  1923.                 value = value_entry.strip()
  1924.             except ValueError:
  1925.                 line = line.replace('\n','')
  1926.                 raise MadGraph5Error, "Could not read line '%s' of Pythia8 card."%\
  1927.                                                                             line
  1928.             # Read a subrun if detected:
  1929.             if param=='Main:subrun':
  1930.                 if read_subrun:
  1931.                     if not started_subrun_reading:
  1932.                         # Record that the subrun reading has started and proceed
  1933.                         started_subrun_reading = True
  1934.                     else:
  1935.                         # We encountered the next subrun. rewind last line and exit
  1936.                         tmpl.seek(last_pos)
  1937.                         break
  1938.                 else:
  1939.                     # Start the reading of this subrun
  1940.                     tmpl.seek(last_pos)
  1941.                     subruns_to_write[int(value)] = StringIO.StringIO()
  1942.                     if int(value) in subruns:
  1943.                         self.subruns[int(value)].write(subruns_to_write[int(value)],
  1944.                                                       tmpl,read_subrun=True)
  1945.                         # Remove this subrun ID from the list
  1946.                         subruns.pop(subruns.index(int(value)))
  1947.                     else:
  1948.                         # Unknow subrun, create a dummy one
  1949.                         DummySubrun=PY8SubRun()
  1950.                         # Remove all of its variables (so that nothing is overwritten)
  1951.                         DummySubrun.clear()
  1952.                         DummySubrun.write(subruns_to_write[int(value)],
  1953.                                 tmpl, read_subrun=True,
  1954.                                 print_only_visible=print_only_visible,
  1955.                                 direct_pythia_input=direct_pythia_input)
  1956.  
  1957.                         logger.info('Adding new unknown subrun with ID %d.'%
  1958.                                                                      int(value))
  1959.                     # Proceed to next line
  1960.                     last_pos = tmpl.tell()
  1961.                     line     = tmpl.readline()
  1962.                     continue
  1963.            
  1964.             # Change parameters which must be output
  1965.             if param in visible_param:
  1966.                 new_value = PY8Card.pythia8_formatting(self[param])
  1967.                 visible_param.pop(visible_param.index(param))
  1968.             elif param in hidden_output_param:
  1969.                 new_value = PY8Card.pythia8_formatting(self[param])
  1970.                 hidden_output_param.pop(hidden_output_param.index(param))
  1971.             else:
  1972.                 # Just copy parameters which don't need to be specified
  1973.                 if param.lower() not in self.params_to_never_write:
  1974.                     output.write(line)
  1975.                 else:
  1976.                     output.write('! The following parameter was forced to be commented out by MG5aMC.\n')
  1977.                     output.write('! %s'%line)
  1978.                 # Proceed to next line
  1979.                 last_pos = tmpl.tell()
  1980.                 line     = tmpl.readline()
  1981.                 continue
  1982.            
  1983.             # Substitute the value.
  1984.             # If it is directly the pytia input, then don't write the param if it
  1985.             # is not in the list of visible_params_to_always_write and was
  1986.             # not user_set or system_set
  1987.             if ((not direct_pythia_input) or
  1988.                   (param.lower() in self.visible_params_to_always_write) or
  1989.                   (param.lower() in self.user_set) or
  1990.                   (param.lower() in self.system_set)):
  1991.                 template = '%s=%s'
  1992.             else:
  1993.                 # These are parameters that the user can edit in AskEditCards
  1994.                 # but if neither the user nor the system edited them,
  1995.                 # then they shouldn't be passed to Pythia
  1996.                 template = '!%s=%s'
  1997.  
  1998.             output.write(template%(param_entry,
  1999.                                   value_entry.replace(value,new_value)))
  2000.        
  2001.             # Proceed to next line
  2002.             last_pos = tmpl.tell()
  2003.             line     = tmpl.readline()
  2004.        
  2005.         # If add_missing is False, make sure to empty the list of remaining parameters
  2006.         if not add_missing:
  2007.             visible_param = []
  2008.             hidden_output_param = []
  2009.        
  2010.         # Now output the missing parameters. Warn about visible ones.
  2011.         if len(visible_param)>0 and not template is None:
  2012.             output.write(
  2013. """!
  2014. ! Additional general parameters%s.
  2015. !
  2016. """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else ''))
  2017.         for param in visible_param:
  2018.             value = PY8Card.pythia8_formatting(self[param])
  2019.             output.write('%s=%s\n'%(param,value))
  2020.             if template is None:
  2021.                 if param=='Main:subrun':
  2022.                     output.write(
  2023. """!
  2024. !  Definition of subrun %d
  2025. !
  2026. """%self['Main:subrun'])
  2027.             elif param.lower() not in self.hidden_param:
  2028.                 logger.debug('Adding parameter %s (missing in the template) to current '+\
  2029.                                     'pythia8 card (with value %s)',param, value)
  2030.  
  2031.         if len(hidden_output_param)>0 and not template is None:
  2032.             output.write(
  2033. """!
  2034. ! Additional technical parameters%s set by MG5_aMC.
  2035. !
  2036. """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else ''))
  2037.         for param in hidden_output_param:
  2038.             if param.lower() in self.comments:
  2039.                 comment = '\n'.join('! %s'%c for c in
  2040.                           self.comments[param.lower()].split('\n'))
  2041.                 output.write(comment+'\n')
  2042.             output.write('%s=%s\n'%(param,PY8Card.pythia8_formatting(self[param])))
  2043.        
  2044.         # Don't close the file if we were reading a subrun, but simply write
  2045.         # output and return now
  2046.         if read_subrun:
  2047.             output_file.write(output.getvalue())
  2048.             return
  2049.  
  2050.         # Now add subruns not present in the template
  2051.         for subrunID in subruns:
  2052.             new_subrun = StringIO.StringIO()
  2053.             self.subruns[subrunID].write(new_subrun,None,read_subrun=True)
  2054.             subruns_to_write[subrunID] = new_subrun
  2055.  
  2056.         # Add all subruns to the output, in the right order
  2057.         for subrunID in sorted(subruns_to_write):
  2058.             output.write(subruns_to_write[subrunID].getvalue())
  2059.  
  2060.         # If 'LHEFInputs:nSubruns' is not user_set, then make sure it is
  2061.         # updated at least larger or equal to the maximum SubRunID
  2062.         if 'LHEFInputs:nSubruns'.lower() not in self.user_set and \
  2063.              len(subruns_to_write)>0 and 'LHEFInputs:nSubruns' in self\
  2064.              and self['LHEFInputs:nSubruns']<max(subruns_to_write.keys()):
  2065.             logger.info("Updating PY8 parameter 'LHEFInputs:nSubruns' to "+
  2066.           "%d so as to cover all defined subruns."%max(subruns_to_write.keys()))
  2067.             self['LHEFInputs:nSubruns'] = max(subruns_to_write.keys())
  2068.             output = StringIO.StringIO()
  2069.             self.write(output,template,print_only_visible=print_only_visible)
  2070.  
  2071.         # Write output
  2072.         if isinstance(output_file, str):
  2073.             out = open(output_file,'w')
  2074.             out.write(output.getvalue())
  2075.             out.close()
  2076.         else:
  2077.             output_file.write(output.getvalue())
  2078.        
  2079.     def read(self, file_input, read_subrun=False, setter='default'):
  2080.         """Read the input file, this can be a path to a file,
  2081.           a file object, a str with the content of the file.
  2082.           The setter option choses the authority that sets potential
  2083.           modified/new parameters. It can be either:
  2084.             'default' or 'user' or 'system'"""
  2085.         if isinstance(file_input, str):
  2086.             if "\n" in file_input:
  2087.                 finput = StringIO.StringIO(file_input)
  2088.             elif os.path.isfile(file_input):
  2089.                 finput = open(file_input)
  2090.             else:
  2091.                 raise Exception, "File input '%s' not found." % file_input
  2092.         elif isinstance(file_input, (StringIO.StringIO, file)):
  2093.             finput = file_input
  2094.         else:
  2095.             raise MadGraph5Error("Incorrect type for argument 'file_input': %s"%
  2096.                                                     file_input.__class__.__name__)
  2097.  
  2098.         # Read the template
  2099.         last_pos = finput.tell()
  2100.         line     = finput.readline()
  2101.         started_subrun_reading = False
  2102.         while line!='':
  2103.             # Skip comments
  2104.             if line.strip().startswith('!') or line.strip()=='':
  2105.                 # proceed to next line
  2106.                 last_pos = finput.tell()
  2107.                 line     = finput.readline()
  2108.                 continue
  2109.             # Read parameter
  2110.             try:
  2111.                 param, value = line.split('=',1)
  2112.                 param = param.strip()
  2113.                 value = value.strip()
  2114.             except ValueError:
  2115.                 line = line.replace('\n','')
  2116.                 raise MadGraph5Error, "Could not read line '%s' of Pythia8 card."%\
  2117.                                                                           line
  2118.             if '!' in value:
  2119.                 value,_ = value.split('!',1)                                                            
  2120.                                                                          
  2121.             # Read a subrun if detected:
  2122.             if param=='Main:subrun':
  2123.                 if read_subrun:
  2124.                     if not started_subrun_reading:
  2125.                         # Record that the subrun reading has started and proceed
  2126.                         started_subrun_reading = True
  2127.                     else:
  2128.                         # We encountered the next subrun. rewind last line and exit
  2129.                         finput.seek(last_pos)
  2130.                         return
  2131.                 else:
  2132.                     # Start the reading of this subrun
  2133.                     finput.seek(last_pos)
  2134.                     if int(value) in self.subruns:
  2135.                         self.subruns[int(value)].read(finput,read_subrun=True,
  2136.                                                                   setter=setter)
  2137.                     else:
  2138.                         # Unknow subrun, create a dummy one
  2139.                         NewSubrun=PY8SubRun()
  2140.                         NewSubrun.read(finput,read_subrun=True, setter=setter)
  2141.                         self.add_subrun(NewSubrun)
  2142.  
  2143.                     # proceed to next line
  2144.                     last_pos = finput.tell()
  2145.                     line     = finput.readline()
  2146.                     continue
  2147.            
  2148.             # Read parameter. The case of a parameter not defined in the card is
  2149.             # handled directly in ConfigFile.
  2150.  
  2151.             # Use the appropriate authority to set the new/changed variable
  2152.             if setter == 'user':
  2153.                 self.userSet(param,value)
  2154.             elif setter == 'system':
  2155.                 self.systemSet(param,value)
  2156.             else:
  2157.                 self.defaultSet(param,value)
  2158.  
  2159.             # proceed to next line
  2160.             last_pos = finput.tell()
  2161.             line     = finput.readline()
  2162.  
  2163. class PY8SubRun(PY8Card):
  2164.     """ Class to characterize a specific PY8 card subrun section. """
  2165.  
  2166.     def add_default_subruns(self, type):
  2167.         """ Overloading of the homonym function called in the __init__ of PY8Card.
  2168.        The initialization of the self.subruns attribute should of course not
  2169.        be performed in PY8SubRun."""
  2170.         pass
  2171.  
  2172.     def __init__(self, *args, **opts):
  2173.         """ Initialize a subrun """
  2174.        
  2175.         # Force user to set it manually.
  2176.         subrunID = -1
  2177.         if 'subrun_id' in opts:
  2178.             subrunID = opts.pop('subrun_id')
  2179.  
  2180.         super(PY8SubRun, self).__init__(*args, **opts)
  2181.         self['Main:subrun']=subrunID
  2182.  
  2183.     def default_setup(self):
  2184.         """Sets up the list of available PY8SubRun parameters."""
  2185.        
  2186.         # Add all default PY8Card parameters
  2187.         super(PY8SubRun, self).default_setup()
  2188.         # Make sure they are all hidden
  2189.         self.hidden_param = [k.lower() for k in self.keys()]
  2190.         self.hidden_params_to_always_write = set()
  2191.         self.visible_params_to_always_write = set()
  2192.  
  2193.         # Now add Main:subrun and Beams:LHEF. They are not hidden.
  2194.         self.add_param("Main:subrun", -1)
  2195.         self.add_param("Beams:LHEF", "events.lhe.gz")
  2196.  
  2197.  
  2198.  
  2199. runblock = collections.namedtuple('block', ('name', 'fields', 'template_on', 'template_off'))
  2200. class RunCard(ConfigFile):
  2201.  
  2202.     filename = 'run_card'
  2203.     blocks = []
  2204.                                    
  2205.     def __new__(cls, finput=None, **opt):
  2206.         if cls is RunCard:
  2207.             if not finput:
  2208.                 target_class = RunCardLO
  2209.             elif isinstance(finput, cls):
  2210.                 target_class = finput.__class__
  2211.             elif isinstance(finput, str):
  2212.                 if '\n' not in finput:
  2213.                     finput = open(finput).read()
  2214.                 if 'req_acc_FO' in finput:
  2215.                     target_class = RunCardNLO
  2216.                 else:
  2217.                     target_class = RunCardLO
  2218.             else:
  2219.                 return None
  2220.             return super(RunCard, cls).__new__(target_class, finput, **opt)
  2221.         else:
  2222.             return super(RunCard, cls).__new__(cls, finput, **opt)
  2223.  
  2224.     def __init__(self, *args, **opts):
  2225.        
  2226.         # The following parameter are updated in the defaultsetup stage.
  2227.        
  2228.         #parameter for which no warning should be raised if not define
  2229.         self.hidden_param = []
  2230.         # in which include file the parameer should be written
  2231.         self.includepath = collections.defaultdict(list)
  2232.         #some parameter have different name in fortran code
  2233.         self.fortran_name = {}
  2234.         #parameter which are not supported anymore. (no action on the code)
  2235.         self.legacy_parameter = {}
  2236.         #a list with all the cuts variable
  2237.         self.cuts_parameter = []
  2238.         # parameter added where legacy requires an older value.
  2239.         self.system_default = {}
  2240.        
  2241.         self.display_block = [] # set some block to be displayed
  2242.         self.warned=False
  2243.  
  2244.  
  2245.         super(RunCard, self).__init__(*args, **opts)
  2246.  
  2247.     def add_param(self, name, value, fortran_name=None, include=True,
  2248.                   hidden=False, legacy=False, cut=False, system=False, sys_default=None,
  2249.                   **opts):
  2250.         """ add a parameter to the card. value is the default value and
  2251.        defines the type (int/float/bool/str) of the input.
  2252.        fortran_name defines what is the associate name in the f77 code
  2253.        include defines if we have to put the value in the include file
  2254.        hidden defines if the parameter is expected to be define by the user.
  2255.        legacy:Parameter which is not used anymore (raise a warning if not default)
  2256.        cut: defines the list of cut parameter to allow to set them all to off.
  2257.        sys_default: default used if the parameter is not in the card
  2258.        
  2259.        options of **opts:
  2260.        - allowed: list of valid options. '*' means anything else should be allowed.
  2261.                 empty list means anything possible as well.
  2262.        - comment: add comment for writing/help
  2263.        - typelist: type of the list if default is empty
  2264.        """
  2265.  
  2266.         super(RunCard, self).add_param(name, value, system=system,**opts)
  2267.         name = name.lower()
  2268.         if fortran_name:
  2269.             self.fortran_name[name] = fortran_name
  2270.         if legacy:
  2271.             self.legacy_parameter[name] = value
  2272.             include = False
  2273.         self.includepath[include].append(name)
  2274.         if hidden or system:
  2275.             self.hidden_param.append(name)
  2276.         if cut:
  2277.             self.cuts_parameter.append(name)
  2278.         if sys_default is not None:
  2279.             self.system_default[name] = sys_default
  2280.  
  2281.        
  2282.  
  2283.     def read(self, finput, consistency=True):
  2284.         """Read the input file, this can be a path to a file,
  2285.           a file object, a str with the content of the file."""
  2286.            
  2287.         if isinstance(finput, str):
  2288.             if "\n" in finput:
  2289.                 finput = finput.split('\n')
  2290.             elif os.path.isfile(finput):
  2291.                 finput = open(finput)
  2292.             else:
  2293.                 raise Exception, "No such file %s" % finput
  2294.        
  2295.         for line in finput:
  2296.             line = line.split('#')[0]
  2297.             line = line.split('!')[0]
  2298.             line = line.rsplit('=',1)
  2299.             if len(line) != 2:
  2300.                 continue
  2301.             value, name = line
  2302.             name = name.lower().strip()
  2303.             if name not in self and ('min' in name or 'max' in name):
  2304.                 #looks like an entry added by one user -> add it nicely
  2305.                 self.add_param(name, float(value), hidden=True, cut=True)
  2306.             else:
  2307.                 self.set( name, value, user=True)
  2308.         # parameter not set in the run_card can be set to compatiblity value
  2309.         if consistency:
  2310.                 try:
  2311.                     self.check_validity()
  2312.                 except InvalidRunCard, error:
  2313.                     if consistency == 'warning':
  2314.                         logger.warning(str(error))
  2315.                     else:
  2316.                         raise
  2317.                    
  2318.                
  2319.     def write(self, output_file, template=None, python_template=False,
  2320.                     write_hidden=False):
  2321.         """Write the run_card in output_file according to template
  2322.           (a path to a valid run_card)"""
  2323.  
  2324.         to_write = set(self.user_set)
  2325.         written = set()
  2326.         if not template:
  2327.             raise Exception
  2328.  
  2329.         # check which optional block to write:
  2330.         write_block= []
  2331.         for b in self.blocks:
  2332.             name = b.name
  2333.             # check if the block has to be written
  2334.             if name not in self.display_block and \
  2335.                not any(f in self.user_set for f in b.fields):
  2336.                 continue
  2337.             write_block.append(b.name)
  2338.        
  2339.         if python_template and not to_write:
  2340.             import string
  2341.             text = file(template,'r').read()
  2342.             if self.blocks:
  2343.                 text = string.Template(text)
  2344.                 mapping = {}
  2345.                 for b in self.blocks:
  2346.                     if b.name in write_block:
  2347.                         mapping[b.name] = b.template_on
  2348.                     else:
  2349.                         mapping[b.name] = b.template_off
  2350.                 text = text.substitute(mapping)
  2351.  
  2352.             if not self.list_parameter:
  2353.                 text = text % self
  2354.             else:
  2355.                 data = dict(self)                
  2356.                 for name in self.list_parameter:
  2357.                     if self.list_parameter[name] != str:
  2358.                         data[name] = ', '.join(str(v) for v in data[name])
  2359.                     else:
  2360.                         data[name] = "['%s']" % "', '".join(str(v) for v in data[name])
  2361.                 text = text % data
  2362.         else:                        
  2363.             text = ""
  2364.             for line in file(template,'r'):                  
  2365.                 nline = line.split('#')[0]
  2366.                 nline = nline.split('!')[0]
  2367.                 comment = line[len(nline):]
  2368.                 nline = nline.split('=')
  2369.                 if python_template and nline[0].startswith('$'):
  2370.                     block_name = nline[0][1:]
  2371.                     this_group = [b for b in self.blocks if b.name == block_name]
  2372.                     if not this_group:
  2373.                         logger.debug("block %s not defined", block_name)
  2374.                         continue
  2375.                     else:
  2376.                         this_group = this_group[0]
  2377.                     if block_name in write_block:
  2378.                         text += this_group.template_on % self
  2379.                         for name in this_group.fields:
  2380.                             written.add(name)
  2381.                             if name in to_write:
  2382.                                 to_write.remove(name)
  2383.                     else:
  2384.                         text += this_group.template_off % self
  2385.                    
  2386.                 elif len(nline) != 2:
  2387.                     text += line
  2388.                 elif nline[1].strip() in self:
  2389.                     name = nline[1].strip().lower()
  2390.                     value = self[name]
  2391.                     if name in self.list_parameter:
  2392.                         if self.list_parameter[name] != str:
  2393.                             value = ', '.join([str(v) for v in value])
  2394.                         else:
  2395.                             value =  "['%s']" % "', '".join(str(v) for v in value)
  2396.                     if python_template:
  2397.                         text += line % {nline[1].strip():value, name:value}
  2398.                         written.add(name)
  2399.                     else:
  2400.                         if not comment or comment[-1]!='\n':
  2401.                             endline = '\n'
  2402.                         else:
  2403.                             endline = ''
  2404.                         text += '  %s\t= %s %s%s' % (value, name, comment, endline)
  2405.                         written.add(name)                        
  2406.  
  2407.                     if name in to_write:
  2408.                         to_write.remove(name)
  2409.                 else:
  2410.                     logger.info('Adding missing parameter %s to current %s (with default value)',
  2411.                                  (name, self.filename))
  2412.                     written.add(name)
  2413.                     text += line
  2414.  
  2415.             for b in self.blocks:
  2416.                 if b.name not in write_block:
  2417.                     continue
  2418.                 # check if all attribute of the block have been written already
  2419.                 if all(f in written for f in b.fields):
  2420.                     continue
  2421.  
  2422.                 to_add = []
  2423.                 for line in b.template_on.split('\n'):                  
  2424.                     nline = line.split('#')[0]
  2425.                     nline = nline.split('!')[0]
  2426.                     nline = nline.split('=')
  2427.                     if len(nline) != 2:
  2428.                         to_add.append(line)
  2429.                     elif nline[1].strip() in self:
  2430.                         name = nline[1].strip().lower()
  2431.                         value = self[name]
  2432.                         if name in self.list_parameter:
  2433.                             value = ', '.join([str(v) for v in value])
  2434.                         if name in written:
  2435.                             continue #already include before
  2436.                         else:
  2437.                             to_add.append(line % {nline[1].strip():value, name:value})
  2438.                             written.add(name)                        
  2439.    
  2440.                         if name in to_write:
  2441.                             to_write.remove(name)
  2442.                     else:
  2443.                         raise Exception
  2444.                
  2445.                 if b.template_off in text:
  2446.                     text = text.replace(b.template_off, '\n'.join(to_add))
  2447.                 else:
  2448.                     text += '\n'.join(to_add)
  2449.  
  2450.         if to_write or write_hidden:
  2451.             text+="""#*********************************************************************
  2452. #  Additional hidden parameters
  2453. #*********************************************************************
  2454. """            
  2455.             if write_hidden:
  2456.                 #
  2457.                 # do not write hidden parameter not hidden for this template
  2458.                 #
  2459.                 if python_template:
  2460.                     written = written.union(set(re.findall('\%\((\w*)\)s', file(template,'r').read(), re.M)))
  2461.                 to_write = to_write.union(set(self.hidden_param))
  2462.                 to_write = to_write.difference(written)
  2463.  
  2464.             for key in to_write:
  2465.                 if key in self.system_only:
  2466.                     continue
  2467.  
  2468.                 comment = self.comments.get(key,'hidden_parameter').replace('\n','\n#')
  2469.                 text += '  %s\t= %s # %s\n' % (self[key], key, comment)
  2470.  
  2471.         if isinstance(output_file, str):
  2472.             fsock = open(output_file,'w')
  2473.             fsock.write(text)
  2474.             fsock.close()
  2475.         else:
  2476.             output_file.write(text)
  2477.  
  2478.  
  2479.     def get_default(self, name, default=None, log_level=None):
  2480.         """return self[name] if exist otherwise default. log control if we
  2481.        put a warning or not if we use the default value"""
  2482.  
  2483.         lower_name = name.lower()
  2484.         if lower_name not in self.user_set:
  2485.             if log_level is None:
  2486.                 if lower_name in self.system_only:
  2487.                     log_level = 5
  2488.                 elif lower_name in self.auto_set:
  2489.                     log_level = 5
  2490.                 elif lower_name in self.hidden_param:
  2491.                     log_level = 10
  2492.                 else:
  2493.                     log_level = 20
  2494.             if not default:
  2495.                 default = dict.__getitem__(self, name.lower())
  2496.  
  2497.             logger.log(log_level, '%s missed argument %s. Takes default: %s'
  2498.                                    % (self.filename, name, default))
  2499.             self[name] = default
  2500.             return default
  2501.         else:
  2502.             return self[name]  
  2503.  
  2504.    
  2505.     @staticmethod
  2506.     def f77_formatting(value, formatv=None):
  2507.         """format the variable into fortran. The type is detected by default"""
  2508.  
  2509.         if not formatv:
  2510.             if isinstance(value, bool):
  2511.                 formatv = 'bool'
  2512.             elif isinstance(value, int):
  2513.                 formatv = 'int'
  2514.             elif isinstance(value, float):
  2515.                 formatv = 'float'
  2516.             elif isinstance(value, str):
  2517.                 formatv = 'str'
  2518.             else:
  2519.                 logger.debug("unknow format for f77_formatting: %s" , str(value))
  2520.                 formatv = 'str'
  2521.         else:
  2522.             assert formatv
  2523.            
  2524.         if formatv == 'bool':
  2525.             if str(value) in ['1','T','.true.','True']:
  2526.                 return '.true.'
  2527.             else:
  2528.                 return '.false.'
  2529.            
  2530.         elif formatv == 'int':
  2531.             try:
  2532.                 return str(int(value))
  2533.             except ValueError:
  2534.                 fl = float(value)
  2535.                 if int(fl) == fl:
  2536.                     return str(int(fl))
  2537.                 else:
  2538.                     raise
  2539.                
  2540.         elif formatv == 'float':
  2541.             if isinstance(value, str):
  2542.                 value = value.replace('d','e')
  2543.             return ('%.10e' % float(value)).replace('e','d')
  2544.        
  2545.         elif formatv == 'str':
  2546.             # Check if it is a list
  2547.             if value.strip().startswith('[') and value.strip().endswith(']'):
  2548.                 elements = (value.strip()[1:-1]).split()
  2549.                 return ['_length = %d'%len(elements)]+\
  2550.                        ['(%d) = %s'%(i+1, elem.strip()) for i, elem in \
  2551.                                                             enumerate(elements)]
  2552.             else:
  2553.                 return "'%s'" % value
  2554.        
  2555.  
  2556.    
  2557.     def check_validity(self, log_level=30):
  2558.         """check that parameter missing in the card are set to the expected value"""
  2559.  
  2560.         for name, value in self.system_default.items():
  2561.                 self.set(name, value, changeifuserset=False)
  2562.        
  2563.  
  2564.         for name in self.includepath[False]:
  2565.             to_bypass = self.hidden_param + self.legacy_parameter.keys()
  2566.             if name not in to_bypass:
  2567.                 self.get_default(name, log_level=log_level)
  2568.  
  2569.         for name in self.legacy_parameter:
  2570.             if self[name] != self.legacy_parameter[name]:
  2571.                 logger.warning("The parameter %s is not supported anymore this parameter will be ignored." % name)
  2572.                
  2573.     default_include_file = 'run_card.inc'
  2574.  
  2575.     def update_system_parameter_for_include(self):
  2576.         """update hidden system only parameter for the correct writtin in the
  2577.        include"""
  2578.         return
  2579.  
  2580.     def write_include_file(self, output_dir):
  2581.         """Write the various include file in output_dir.
  2582.        The entry True of self.includepath will be written in run_card.inc
  2583.        The entry False will not be written anywhere"""
  2584.        
  2585.         # ensure that all parameter are coherent and fix those if needed
  2586.         self.check_validity()
  2587.        
  2588.         #ensusre that system only parameter are correctly set
  2589.         self.update_system_parameter_for_include()
  2590.        
  2591.         for incname in self.includepath:
  2592.             if incname is True:
  2593.                 pathinc = self.default_include_file
  2594.             elif incname is False:
  2595.                 continue
  2596.             else:
  2597.                 pathinc = incname
  2598.                
  2599.             fsock = file_writers.FortranWriter(pjoin(output_dir,pathinc))  
  2600.             for key in self.includepath[incname]:                
  2601.                 #define the fortran name
  2602.                 if key in self.fortran_name:
  2603.                     fortran_name = self.fortran_name[key]
  2604.                 else:
  2605.                     fortran_name = key
  2606.                    
  2607.                 #get the value with warning if the user didn't set it
  2608.                 value = self.get_default(key)
  2609.                 # Special treatment for strings containing a list of
  2610.                 # strings. Convert it to a list of strings
  2611.                 if isinstance(value, list):
  2612.                     # in case of a list, add the length of the list as 0th
  2613.                     # element in fortran. Only in case of integer or float
  2614.                     # list (not for bool nor string)
  2615.                     targettype = self.list_parameter[key]                        
  2616.                     if targettype is bool:
  2617.                         pass
  2618.                     elif targettype is int:
  2619.                         line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(len(value)))
  2620.                         fsock.writelines(line)
  2621.                     elif targettype is float:
  2622.                         line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(float(len(value))))
  2623.                         fsock.writelines(line)
  2624.                     # output the rest of the list in fortran
  2625.                     for i,v in enumerate(value):
  2626.                         line = '%s(%s) = %s \n' % (fortran_name, i+1, self.f77_formatting(v))
  2627.                         fsock.writelines(line)
  2628.                 elif isinstance(value, dict):
  2629.                     for fortran_name, onevalue in value.items():
  2630.                         line = '%s = %s \n' % (fortran_name, self.f77_formatting(onevalue))
  2631.                         fsock.writelines(line)                      
  2632.                 else:
  2633.                     line = '%s = %s \n' % (fortran_name, self.f77_formatting(value))
  2634.                     fsock.writelines(line)
  2635.             fsock.close()  
  2636.  
  2637.     @staticmethod
  2638.     def get_idbmup(lpp):
  2639.         """return the particle colliding pdg code"""
  2640.         if lpp in (1,2, -1,-2):
  2641.             return math.copysign(2212, lpp)
  2642.         elif lpp in (3,-3):
  2643.             return math.copysign(11, lpp)
  2644.         elif lpp == 0:
  2645.             #logger.critical("Fail to write correct idbmup in the lhe file. Please correct those by hand")
  2646.             return 0
  2647.         else:
  2648.             return lpp
  2649.  
  2650.     def get_banner_init_information(self):
  2651.         """return a dictionary with the information needed to write
  2652.        the first line of the <init> block of the lhe file."""
  2653.        
  2654.         output = {}
  2655.         output["idbmup1"] = self.get_idbmup(self['lpp1'])
  2656.         output["idbmup2"] = self.get_idbmup(self['lpp2'])
  2657.         output["ebmup1"] = self["ebeam1"]
  2658.         output["ebmup2"] = self["ebeam2"]
  2659.         output["pdfgup1"] = 0
  2660.         output["pdfgup2"] = 0
  2661.         output["pdfsup1"] = self.get_pdf_id(self["pdlabel"])
  2662.         output["pdfsup2"] = self.get_pdf_id(self["pdlabel"])
  2663.         return output
  2664.    
  2665.     def get_pdf_id(self, pdf):
  2666.         if pdf == "lhapdf":
  2667.             lhaid = self["lhaid"]
  2668.             if isinstance(lhaid, list):
  2669.                 return lhaid[0]
  2670.             else:
  2671.                 return lhaid
  2672.         else:
  2673.             return {'none': 0,
  2674.                     'cteq6_m':10000,'cteq6_l':10041,'cteq6l1':10042,
  2675.                     'nn23lo':246800,'nn23lo1':247000,'nn23nlo':244800
  2676.                     }[pdf]    
  2677.    
  2678.     def get_lhapdf_id(self):
  2679.         return self.get_pdf_id(self['pdlabel'])
  2680.  
  2681.     def remove_all_cut(self):
  2682.         """remove all the cut"""
  2683.  
  2684.         for name in self.cuts_parameter:
  2685.             targettype = type(self[name])
  2686.             if targettype == bool:
  2687.                 self[name] = False
  2688.             elif 'min' in name:
  2689.                 self[name] = 0
  2690.             elif 'max' in name:
  2691.                 self[name] = -1
  2692.             elif 'eta' in name:
  2693.                 self[name] = -1
  2694.             else:
  2695.                 self[name] = 0      
  2696.  
  2697. class RunCardLO(RunCard):
  2698.     """an object to handle in a nice way the run_card information"""
  2699.    
  2700.     blocks = [
  2701. #    HEAVY ION OPTIONAL BLOCK            
  2702.         runblock(name='ion_pdf', fields=('nb_neutron1', 'nb_neutron2','nb_proton1','nb_proton2','mass_ion1', 'mass_ion2'),
  2703.             template_on=\
  2704. """#*********************************************************************
  2705. # Heavy ion PDF / rescaling of PDF                                   *
  2706. #*********************************************************************
  2707.  %(nb_proton1)s    = nb_proton1 # number of proton for the first beam
  2708.  %(nb_neutron1)s    = nb_neutron1 # number of neutron for the first beam
  2709.  %(mass_ion1)s = mass_ion1 # mass of the heavy ion (first beam)
  2710. # Note that seting differently the two beams only work if you use
  2711. # group_subprocess=False when generating your matrix-element
  2712.  %(nb_proton2)s    = nb_proton2 # number of proton for the second beam
  2713.  %(nb_neutron2)s    = nb_neutron2 # number of neutron for the second beam
  2714.  %(mass_ion2)s = mass_ion2 # mass of the heavy ion (second beam)  
  2715. """,
  2716.             template_off='# To see heavy ion options: type "update ion_pdf"'),
  2717.              
  2718.              
  2719. #    BEAM POLARIZATION OPTIONAL BLOCK
  2720.         runblock(name='beam_pol', fields=('polbeam1','polbeam2'),
  2721.             template_on=\
  2722. """#*********************************************************************
  2723. # Beam polarization from -100 (left-handed) to 100 (right-handed)    *
  2724. #*********************************************************************
  2725.     %(polbeam1)s     = polbeam1 ! beam polarization for beam 1
  2726.     %(polbeam2)s     = polbeam2 ! beam polarization for beam 2
  2727. """,                                              
  2728.             template_off='# To see polarised beam options: type "update beam_pol"'),
  2729.  
  2730. #    SYSCALC OPTIONAL BLOCK              
  2731.         runblock(name='syscalc', fields=('sys_scalefact', 'sys_alpsfact','sys_matchscale','sys_pdf'),
  2732.               template_on=\
  2733. """#**************************************
  2734. # Parameter below of the systematics study
  2735. #  will be used by SysCalc (if installed)
  2736. #**************************************
  2737. #
  2738. %(sys_scalefact)s = sys_scalefact  # factorization/renormalization scale factor
  2739. %(sys_alpsfact)s = sys_alpsfact  # \alpha_s emission scale factors
  2740. %(sys_matchscale)s = sys_matchscale # variation of merging scale
  2741. # PDF sets and number of members (0 or none for all members).
  2742. %(sys_pdf)s = sys_pdf # list of pdf sets. (errorset not valid for syscalc)
  2743. # MSTW2008nlo68cl.LHgrid 1  = sys_pdf
  2744. #
  2745. """,
  2746.     template_off= '# Syscalc is deprecated but to see the associate options type\'update syscalc\''),
  2747.     ]
  2748.    
  2749.    
  2750.    
  2751.     def default_setup(self):
  2752.         """default value for the run_card.dat"""
  2753.        
  2754.         self.add_param("run_tag", "tag_1", include=False)
  2755.         self.add_param("gridpack", False)
  2756.         self.add_param("time_of_flight", -1.0, include=False)
  2757.         self.add_param("nevents", 10000)        
  2758.         self.add_param("iseed", 0)
  2759.         self.add_param("python_seed", -2, include=False, hidden=True, comment="controlling python seed [handling in particular the final unweighting].\n -1 means use default from random module.\n -2 means set to same value as iseed")
  2760.         self.add_param("lpp1", 1, fortran_name="lpp(1)", allowed=[-1,1,0,2,3,9, -2,-3],
  2761.                         comment='first beam energy distribution:\n 0: fixed energy\n 1: PDF from proton\n -1: PDF from anti-proton\n 2:photon from proton, 3:photon from electron, 9: PLUGIN MODE')
  2762.         self.add_param("lpp2", 1, fortran_name="lpp(2)", allowed=[-1,1,0,2,3,9],
  2763.                        comment='first beam energy distribution:\n 0: fixed energy\n 1: PDF from proton\n -1: PDF from anti-proton\n 2:photon from proton, 3:photon from electron, 9: PLUGIN MODE')
  2764.         self.add_param("ebeam1", 6500.0, fortran_name="ebeam(1)")
  2765.         self.add_param("ebeam2", 6500.0, fortran_name="ebeam(2)")
  2766.         self.add_param("polbeam1", 0.0, fortran_name="pb1", hidden=True,
  2767.                                               comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--")
  2768.         self.add_param("polbeam2", 0.0, fortran_name="pb2", hidden=True,
  2769.                                               comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--")
  2770.         self.add_param('nb_proton1', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(1)",
  2771.                        comment='For heavy ion physics nb of proton in the ion (for both beam but if group_subprocess was False)')
  2772.         self.add_param('nb_proton2', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(2)",
  2773.                        comment='For heavy ion physics nb of proton in the ion (used for beam 2 if group_subprocess was False)')
  2774.         self.add_param('nb_neutron1', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(1)",
  2775.                        comment='For heavy ion physics nb of neutron in the ion (for both beam but if group_subprocess was False)')
  2776.         self.add_param('nb_neutron2', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(2)",
  2777.                        comment='For heavy ion physics nb of neutron in the ion (of beam 2 if group_subprocess was False )')        
  2778.         self.add_param('mass_ion1', -1.0, hidden=True, fortran_name="mass_ion(1)",
  2779.                        allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'],
  2780.                        comment='For heavy ion physics mass in GeV of the ion (of beam 1)')
  2781.         self.add_param('mass_ion2', -1.0, hidden=True, fortran_name="mass_ion(2)",
  2782.                        allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'],
  2783.                        comment='For heavy ion physics mass in GeV of the ion (of beam 2)')
  2784.        
  2785.         self.add_param("pdlabel", "nn23lo1", allowed=['lhapdf', 'cteq6_m','cteq6_l', 'cteq6l1','nn23lo', 'nn23lo1', 'nn23nlo']),
  2786.         self.add_param("lhaid", 230000, hidden=True)
  2787.         self.add_param("fixed_ren_scale", False)
  2788.         self.add_param("fixed_fac_scale", False)
  2789.         self.add_param("scale", 91.1880)
  2790.         self.add_param("dsqrt_q2fact1", 91.1880, fortran_name="sf1")
  2791.         self.add_param("dsqrt_q2fact2", 91.1880, fortran_name="sf2")
  2792.         self.add_param("dynamical_scale_choice", -1, comment="\'-1\' is based on CKKW back clustering (following feynman diagram).\n \'1\' is the sum of transverse energy.\n '2' is HT (sum of the transverse mass)\n '3' is HT/2\n '4' is the center of mass energy",
  2793.                                                 allowed=[-1,0,1,2,3,4])
  2794.        
  2795.         # Bias module options
  2796.         self.add_param("bias_module", 'None', include=False)
  2797.         self.add_param('bias_parameters', {'__type__':1.0}, include='BIAS/bias.inc')
  2798.                
  2799.         #matching
  2800.         self.add_param("scalefact", 1.0)
  2801.         self.add_param("ickkw", 0, allowed=[0,1],                               comment="\'0\' for standard fixed order computation.\n\'1\' for MLM merging activates alphas and pdf re-weighting according to a kt clustering of the QCD radiation.")
  2802.         self.add_param("highestmult", 1, fortran_name="nhmult", hidden=True)
  2803.         self.add_param("ktscheme", 1, hidden=True)
  2804.         self.add_param("alpsfact", 1.0)
  2805.         self.add_param("chcluster", False, hidden=True)
  2806.         self.add_param("pdfwgt", True, hidden=True)
  2807.         self.add_param("asrwgtflavor", 5,                                       comment = 'highest quark flavor for a_s reweighting in MLM')
  2808.         self.add_param("clusinfo", True)
  2809.         self.add_param("lhe_version", 3.0)
  2810.         self.add_param("event_norm", "average", allowed=['sum','average', 'unity'],
  2811.                         include=False, sys_default='sum')
  2812.         #cut
  2813.         self.add_param("auto_ptj_mjj", False)
  2814.         self.add_param("bwcutoff", 15.0)
  2815.         self.add_param("cut_decays", False)
  2816.         self.add_param("nhel", 0, include=False)
  2817.         #pt cut
  2818.         self.add_param("ptj", 20.0, cut=True)
  2819.         self.add_param("ptb", 0.0, cut=True)
  2820.         self.add_param("pta", 10.0, cut=True)
  2821.         self.add_param("ptl", 10.0, cut=True)
  2822.         self.add_param("misset", 0.0, cut=True)
  2823.         self.add_param("ptheavy", 0.0, cut=True,                                comment='this cut apply on particle heavier than 10 GeV')
  2824.         self.add_param("ptonium", 1.0, legacy=True)
  2825.         self.add_param("ptjmax", -1.0, cut=True)
  2826.         self.add_param("ptbmax", -1.0, cut=True)
  2827.         self.add_param("ptamax", -1.0, cut=True)
  2828.         self.add_param("ptlmax", -1.0, cut=True)
  2829.         self.add_param("missetmax", -1.0, cut=True)
  2830.         # E cut
  2831.         self.add_param("ej", 0.0, cut=True)
  2832.         self.add_param("eb", 0.0, cut=True)
  2833.         self.add_param("ea", 0.0, cut=True)
  2834.         self.add_param("el", 0.0, cut=True)
  2835.         self.add_param("ejmax", -1.0, cut=True)
  2836.         self.add_param("ebmax", -1.0, cut=True)
  2837.         self.add_param("eamax", -1.0, cut=True)
  2838.         self.add_param("elmax", -1.0, cut=True)
  2839.         # Eta cut
  2840.         self.add_param("etaj", 5.0, cut=True)
  2841.         self.add_param("etab", -1.0, cut=True)
  2842.         self.add_param("etaa", 2.5, cut=True)
  2843.         self.add_param("etal", 2.5, cut=True)
  2844.         self.add_param("etaonium", 0.6, legacy=True)
  2845.         self.add_param("etajmin", 0.0, cut=True)
  2846.         self.add_param("etabmin", 0.0, cut=True)
  2847.         self.add_param("etaamin", 0.0, cut=True)
  2848.         self.add_param("etalmin", 0.0, cut=True)
  2849.         # DRJJ
  2850.         self.add_param("drjj", 0.4, cut=True)
  2851.         self.add_param("drbb", 0.0, cut=True)
  2852.         self.add_param("drll", 0.4, cut=True)
  2853.         self.add_param("draa", 0.4, cut=True)
  2854.         self.add_param("drbj", 0.0, cut=True)
  2855.         self.add_param("draj", 0.4, cut=True)
  2856.         self.add_param("drjl", 0.4, cut=True)
  2857.         self.add_param("drab", 0.0, cut=True)
  2858.         self.add_param("drbl", 0.0, cut=True)
  2859.         self.add_param("dral", 0.4, cut=True)
  2860.         self.add_param("drjjmax", -1.0, cut=True)
  2861.         self.add_param("drbbmax", -1.0, cut=True)
  2862.         self.add_param("drllmax", -1.0, cut=True)
  2863.         self.add_param("draamax", -1.0, cut=True)
  2864.         self.add_param("drbjmax", -1.0, cut=True)
  2865.         self.add_param("drajmax", -1.0, cut=True)
  2866.         self.add_param("drjlmax", -1.0, cut=True)
  2867.         self.add_param("drabmax", -1.0, cut=True)
  2868.         self.add_param("drblmax", -1.0, cut=True)
  2869.         self.add_param("dralmax", -1.0, cut=True)
  2870.         # invariant mass
  2871.         self.add_param("mmjj", 0.0, cut=True)
  2872.         self.add_param("mmbb", 0.0, cut=True)
  2873.         self.add_param("mmaa", 0.0, cut=True)
  2874.         self.add_param("mmll", 0.0, cut=True)
  2875.         self.add_param("mmjjmax", -1.0, cut=True)
  2876.         self.add_param("mmbbmax", -1.0, cut=True)                
  2877.         self.add_param("mmaamax", -1.0, cut=True)
  2878.         self.add_param("mmllmax", -1.0, cut=True)
  2879.         self.add_param("mmnl", 0.0, cut=True)
  2880.         self.add_param("mmnlmax", -1.0, cut=True)
  2881.         #minimum/max pt for sum of leptons
  2882.         self.add_param("ptllmin", 0.0, cut=True)
  2883.         self.add_param("ptllmax", -1.0, cut=True)
  2884.         self.add_param("xptj", 0.0, cut=True)
  2885.         self.add_param("xptb", 0.0, cut=True)
  2886.         self.add_param("xpta", 0.0, cut=True)
  2887.         self.add_param("xptl", 0.0, cut=True)
  2888.         # ordered pt jet
  2889.         self.add_param("ptj1min", 0.0, cut=True)
  2890.         self.add_param("ptj1max", -1.0, cut=True)
  2891.         self.add_param("ptj2min", 0.0, cut=True)
  2892.         self.add_param("ptj2max", -1.0, cut=True)
  2893.         self.add_param("ptj3min", 0.0, cut=True)
  2894.         self.add_param("ptj3max", -1.0, cut=True)
  2895.         self.add_param("ptj4min", 0.0, cut=True)
  2896.         self.add_param("ptj4max", -1.0, cut=True)                
  2897.         self.add_param("cutuse", 0, cut=True)
  2898.         # ordered pt lepton
  2899.         self.add_param("ptl1min", 0.0, cut=True)
  2900.         self.add_param("ptl1max", -1.0, cut=True)
  2901.         self.add_param("ptl2min", 0.0, cut=True)
  2902.         self.add_param("ptl2max", -1.0, cut=True)
  2903.         self.add_param("ptl3min", 0.0, cut=True)
  2904.         self.add_param("ptl3max", -1.0, cut=True)        
  2905.         self.add_param("ptl4min", 0.0, cut=True)
  2906.         self.add_param("ptl4max", -1.0, cut=True)
  2907.         # Ht sum of jets
  2908.         self.add_param("htjmin", 0.0, cut=True)
  2909.         self.add_param("htjmax", -1.0, cut=True)
  2910.         self.add_param("ihtmin", 0.0, cut=True)
  2911.         self.add_param("ihtmax", -1.0, cut=True)
  2912.         self.add_param("ht2min", 0.0, cut=True)
  2913.         self.add_param("ht3min", 0.0, cut=True)
  2914.         self.add_param("ht4min", 0.0, cut=True)
  2915.         self.add_param("ht2max", -1.0, cut=True)
  2916.         self.add_param("ht3max", -1.0, cut=True)
  2917.         self.add_param("ht4max", -1.0, cut=True)
  2918.         # photon isolation
  2919.         self.add_param("ptgmin", 0.0, cut=True)
  2920.         self.add_param("r0gamma", 0.4)
  2921.         self.add_param("xn", 1.0)
  2922.         self.add_param("epsgamma", 1.0)
  2923.         self.add_param("isoem", True)
  2924.         self.add_param("xetamin", 0.0, cut=True)
  2925.         self.add_param("deltaeta", 0.0, cut=True)
  2926.         self.add_param("ktdurham", -1.0, fortran_name="kt_durham", cut=True)
  2927.         self.add_param("dparameter", 0.4, fortran_name="d_parameter", cut=True)
  2928.         self.add_param("ptlund", -1.0, fortran_name="pt_lund", cut=True)
  2929.         self.add_param("pdgs_for_merging_cut", [21, 1, 2, 3, 4, 5, 6])
  2930.         self.add_param("maxjetflavor", 4)
  2931.         self.add_param("xqcut", 0.0, cut=True)
  2932.         self.add_param("use_syst", True)
  2933.         self.add_param('systematics_program', 'systematics', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics, syscalc')
  2934.         self.add_param('systematics_arguments', ['--mur=0.5,1,2', '--muf=0.5,1,2', '--pdf=errorset'], include=False, hidden=True, comment='Choose the argment to pass to the systematics command. like --mur=0.25,1,4. Look at the help of the systematics function for more details.')
  2935.        
  2936.         self.add_param("sys_scalefact", "0.5 1 2", include=False, hidden=True)
  2937.         self.add_param("sys_alpsfact", "None", include=False, hidden=True)
  2938.         self.add_param("sys_matchscale", "auto", include=False, hidden=True)
  2939.         self.add_param("sys_pdf", "errorset", include=False, hidden=True)
  2940.         self.add_param("sys_scalecorrelation", -1, include=False, hidden=True)
  2941.  
  2942.         #parameter not in the run_card by default
  2943.         self.add_param('gridrun', False, hidden=True)
  2944.         self.add_param('fixed_couplings', True, hidden=True)
  2945.         self.add_param('mc_grouped_subproc', True, hidden=True)
  2946.         self.add_param('xmtcentral', 0.0, hidden=True, fortran_name="xmtc")
  2947.         self.add_param('d', 1.0, hidden=True)
  2948.         self.add_param('gseed', 0, hidden=True, include=False)
  2949.         self.add_param('issgridfile', '', hidden=True)
  2950.         #job handling of the survey/ refine
  2951.         self.add_param('job_strategy', 0, hidden=True, include=False, allowed=[0,1,2], comment='see appendix of 1507.00020 (page 26)')
  2952.         self.add_param('survey_splitting', -1, hidden=True, include=False, comment="for loop-induced control how many core are used at survey for the computation of a single iteration.")
  2953.         self.add_param('survey_nchannel_per_job', 2, hidden=True, include=False, comment="control how many Channel are integrated inside a single job on cluster/multicore")
  2954.         self.add_param('refine_evt_by_job', -1, hidden=True, include=False, comment="control the maximal number of events for the first iteration of the refine (larger means less jobs)")
  2955.         self.add_param('small_width_treatment', 1e-6, hidden=True, comment="generation where the width is below VALUE times mass will be replace by VALUE times mass for the computation. The cross-section will be corrected assuming NWA. Not used for loop-induced process")
  2956.        
  2957.         # parameter allowing to define simple cut via the pdg
  2958.         # Special syntax are related to those. (can not be edit directly)
  2959.         self.add_param('pt_min_pdg',{'__type__':0.}, include=False)
  2960.         self.add_param('pt_max_pdg',{'__type__':0.}, include=False)
  2961.         self.add_param('E_min_pdg',{'__type__':0.}, include=False)
  2962.         self.add_param('E_max_pdg',{'__type__':0.}, include=False)
  2963.         self.add_param('eta_min_pdg',{'__type__':0.}, include=False)
  2964.         self.add_param('eta_max_pdg',{'__type__':0.}, include=False)
  2965.         self.add_param('mxx_min_pdg',{'__type__':0.}, include=False)
  2966.         self.add_param('mxx_only_part_antipart', {'default':False}, include=False)
  2967.        
  2968.         self.add_param('pdg_cut',[0],  system=True) # store which PDG are tracked
  2969.         self.add_param('ptmin4pdg',[0.], system=True) # store pt min
  2970.         self.add_param('ptmax4pdg',[-1.], system=True)
  2971.         self.add_param('Emin4pdg',[0.], system=True) # store pt min
  2972.         self.add_param('Emax4pdg',[-1.], system=True)  
  2973.         self.add_param('etamin4pdg',[0.], system=True) # store pt min
  2974.         self.add_param('etamax4pdg',[-1.], system=True)  
  2975.         self.add_param('mxxmin4pdg',[-1.], system=True)
  2976.         self.add_param('mxxpart_antipart', [False], system=True)
  2977.                      
  2978.              
  2979.     def check_validity(self):
  2980.         """ """
  2981.        
  2982.         super(RunCardLO, self).check_validity()
  2983.        
  2984.         #Make sure that nhel is only either 0 (i.e. no MC over hel) or
  2985.         #1 (MC over hel with importance sampling). In particular, it can
  2986.         #no longer be > 1.
  2987.         if 'nhel' not in self.user_set:
  2988.             raise InvalidRunCard, "Parameter nhel is not defined in the run_card."
  2989.         if self['nhel'] not in [1,0]:
  2990.             raise InvalidRunCard, "Parameter nhel can only be '0' or '1', "+\
  2991.                                                           "not %s." % self['nhel']
  2992.         if int(self['maxjetflavor']) > 6:
  2993.             raise InvalidRunCard, 'maxjetflavor should be lower than 5! (6 is partly supported)'
  2994.  
  2995.         if len(self['pdgs_for_merging_cut']) > 1000:
  2996.             raise InvalidRunCard, "The number of elements in "+\
  2997.                                "'pdgs_for_merging_cut' should not exceed 1000."
  2998.  
  2999.         # some cut need to be deactivated in presence of isolation
  3000.         if self['ptgmin'] > 0:
  3001.             if self['pta'] > 0:
  3002.                 logger.warning('pta cut discarded since photon isolation is used')
  3003.                 self['pta'] = 0.0
  3004.             if self['draj'] > 0:
  3005.                 logger.warning('draj cut discarded since photon isolation is used')
  3006.                 self['draj'] = 0.0  
  3007.        
  3008.         # special treatment for gridpack use the gseed instead of the iseed        
  3009.         if self['gridrun']:
  3010.             self['iseed'] = self['gseed']
  3011.        
  3012.         #Some parameter need to be fixed when using syscalc
  3013.         if self['use_syst']:
  3014.             if self['scalefact'] != 1.0:
  3015.                 logger.warning('Since use_syst=T, We change the value of \'scalefact\' to 1')
  3016.                 self['scalefact'] = 1.0
  3017.      
  3018.         # CKKW Treatment
  3019.         if self['ickkw'] > 0:
  3020.             if self['ickkw'] != 1:
  3021.                 logger.critical('ickkw >1 is pure alpha and only partly implemented.')
  3022.                 import madgraph.interface.extended_cmd as basic_cmd
  3023.                 answer = basic_cmd.smart_input('Do you really want to continue', allow_arg=['y','n'], default='n')
  3024.                 if answer !='y':
  3025.                     raise InvalidRunCard, 'ickkw>1 is still in alpha'
  3026.             if self['use_syst']:
  3027.                 # some additional parameter need to be fixed for Syscalc + matching
  3028.                 if self['alpsfact'] != 1.0:
  3029.                     logger.warning('Since use_syst=T, We change the value of \'alpsfact\' to 1')
  3030.                     self['alpsfact'] =1.0
  3031.             if self['maxjetflavor'] == 6:
  3032.                 raise InvalidRunCard, 'maxjetflavor at 6 is NOT supported for matching!'
  3033.             if self['ickkw'] == 2:
  3034.                 # add warning if ckkw selected but the associate parameter are empty
  3035.                 self.get_default('highestmult', log_level=20)                  
  3036.                 self.get_default('issgridfile', 'issudgrid.dat', log_level=20)
  3037.         if self['xqcut'] > 0:
  3038.             if self['ickkw'] == 0:
  3039.                 logger.error('xqcut>0 but ickkw=0. Potentially not fully consistent setup. Be carefull')
  3040.                 import time
  3041.                 time.sleep(5)
  3042.             if self['drjj'] != 0:
  3043.                 logger.warning('Since icckw>0, We change the value of \'drjj\' to 0')
  3044.                 self['drjj'] = 0
  3045.             if self['drjl'] != 0:
  3046.                 logger.warning('Since icckw>0, We change the value of \'drjl\' to 0')
  3047.                 self['drjl'] = 0    
  3048.             if not self['auto_ptj_mjj']:        
  3049.                 if self['mmjj'] > self['xqcut']:
  3050.                     logger.warning('mmjj > xqcut (and auto_ptj_mjj = F). MMJJ set to 0')
  3051.                     self['mmjj'] = 0.0
  3052.  
  3053.  
  3054.    
  3055.         # check validity of the pdf set
  3056.         if self['pdlabel'] == 'lhapdf':
  3057.             #add warning if lhaid not define
  3058.             self.get_default('lhaid', log_level=20)
  3059.    
  3060.     def update_system_parameter_for_include(self):
  3061.        
  3062.         # set the pdg_for_cut fortran parameter
  3063.         pdg_to_cut = set(self['pt_min_pdg'].keys() +self['pt_max_pdg'].keys() +
  3064.                          self['e_min_pdg'].keys() +self['e_max_pdg'].keys() +
  3065.                          self['eta_min_pdg'].keys() +self['eta_max_pdg'].keys()+
  3066.                          self['mxx_min_pdg'].keys() + self['mxx_only_part_antipart'].keys())
  3067.         pdg_to_cut.discard('__type__')
  3068.         pdg_to_cut.discard('default')
  3069.         if len(pdg_to_cut)>25:
  3070.             raise Exception, "Maximum 25 different pdgs are allowed for pdg specific cut"
  3071.        
  3072.         if any(int(pdg)<0 for pdg in pdg_to_cut):
  3073.             logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
  3074.             raise MadGraph5Error, 'Some PDG specific cuts are defined with negative pdg code'
  3075.        
  3076.        
  3077.         if any(pdg in pdg_to_cut for pdg in [1,2,3,4,5,21,22,11,13,15]):
  3078.             raise Exception, "Can not use PDG related cut for light quark/b quark/lepton/gluon/photon"
  3079.        
  3080.         if pdg_to_cut:
  3081.             self['pdg_cut'] = list(pdg_to_cut)
  3082.             self['ptmin4pdg'] = []
  3083.             self['Emin4pdg'] = []
  3084.             self['etamin4pdg'] =[]
  3085.             self['ptmax4pdg'] = []
  3086.             self['Emax4pdg'] = []
  3087.             self['etamax4pdg'] =[]
  3088.             self['mxxmin4pdg'] =[]
  3089.             self['mxxpart_antipart']  = []
  3090.             for pdg in self['pdg_cut']:
  3091.                 for var in ['pt','e','eta', 'Mxx']:
  3092.                     for minmax in ['min', 'max']:
  3093.                         if var in ['Mxx'] and minmax =='max':
  3094.                             continue
  3095.                         new_var = '%s%s4pdg' % (var, minmax)
  3096.                         old_var = '%s_%s_pdg' % (var, minmax)
  3097.                         default = 0. if minmax=='min' else -1.
  3098.                         self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
  3099.                 #special for mxx_part_antipart
  3100.                 old_var = 'mxx_only_part_antipart'
  3101.                 new_var = 'mxxpart_antipart'
  3102.                 if 'default' in self[old_var]:
  3103.                     default = self[old_var]['default']
  3104.                     self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
  3105.                 else:
  3106.                     if str(pdg) not in self[old_var]:
  3107.                         raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
  3108.                     self[new_var].append(self[old_var][str(pdg)])
  3109.         else:
  3110.             self['pdg_cut'] = [0]
  3111.             self['ptmin4pdg'] = [0.]
  3112.             self['Emin4pdg'] = [0.]
  3113.             self['etamin4pdg'] =[0.]
  3114.             self['ptmax4pdg'] = [-1.]
  3115.             self['Emax4pdg'] = [-1.]
  3116.             self['etamax4pdg'] =[-1.]
  3117.             self['mxxmin4pdg'] =[0.]
  3118.             self['mxxpart_antipart'] = [False]
  3119.            
  3120.                    
  3121.            
  3122.     def create_default_for_process(self, proc_characteristic, history, proc_def):
  3123.         """Rules
  3124.          process 1->N all cut set on off.
  3125.          loop_induced -> MC over helicity
  3126.          e+ e- beam -> lpp:0 ebeam:500
  3127.          p p beam -> set maxjetflavor automatically
  3128.          more than one multiplicity: ickkw=1 xqcut=30 use_syst=F
  3129.         """
  3130.  
  3131.         if proc_characteristic['loop_induced']:
  3132.             self['nhel'] = 1
  3133.         self['pdgs_for_merging_cut'] = proc_characteristic['colored_pdgs']
  3134.                    
  3135.         if proc_characteristic['ninitial'] == 1:
  3136.             #remove all cut
  3137.             self.remove_all_cut()
  3138.             self['use_syst'] = False
  3139.         else:
  3140.             # check for beam_id
  3141.             beam_id = set()
  3142.             for proc in proc_def:
  3143.                 for oneproc in proc:
  3144.                     for leg in oneproc['legs']:
  3145.                         if not leg['state']:
  3146.                             beam_id.add(leg['id'])
  3147.             if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
  3148.                 maxjetflavor = max([4]+[abs(i) for i in beam_id if  -7< i < 7])
  3149.                 self['maxjetflavor'] = maxjetflavor
  3150.                 self['asrwgtflavor'] = maxjetflavor
  3151.                 pass
  3152.             elif 11 in beam_id or -11 in beam_id:
  3153.                 self['lpp1'] = 0
  3154.                 self['lpp2'] = 0
  3155.                 self['ebeam1'] = 500
  3156.                 self['ebeam2'] = 500
  3157.                 self['use_syst'] = False
  3158.             else:
  3159.                 self['lpp1'] = 0
  3160.                 self['lpp2'] = 0    
  3161.                 self['use_syst'] = False            
  3162.                
  3163.         # Check if need matching
  3164.         min_particle = 99
  3165.         max_particle = 0
  3166.         for proc in proc_def:
  3167.             min_particle = min(len(proc[0]['legs']), min_particle)
  3168.             max_particle = max(len(proc[0]['legs']), max_particle)
  3169.         if min_particle != max_particle:
  3170.             #take one of the process with min_particle
  3171.             for procmin in proc_def:
  3172.                 if len(procmin[0]['legs']) != min_particle:
  3173.                     continue
  3174.                 else:
  3175.                     idsmin = [l['id'] for l in procmin[0]['legs']]
  3176.                     break
  3177.             matching = False
  3178.             for procmax in proc_def:
  3179.                 if len(procmax[0]['legs']) != max_particle:
  3180.                     continue
  3181.                 idsmax =  [l['id'] for l in procmax[0]['legs']]
  3182.                 for i in idsmin:
  3183.                     if i not in idsmax:
  3184.                         continue
  3185.                     else:
  3186.                         idsmax.remove(i)
  3187.                 for j in idsmax:
  3188.                     if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
  3189.                         break
  3190.                 else:
  3191.                     # all are jet => matching is ON
  3192.                     matching=True
  3193.                     break
  3194.            
  3195.             if matching:
  3196.                 self['ickkw'] = 1
  3197.                 self['xqcut'] = 30
  3198.                 #self['use_syst'] = False
  3199.                 self['drjj'] = 0
  3200.                 self['drjl'] = 0
  3201.                 self['sys_alpsfact'] = "0.5 1 2"
  3202.                
  3203.         # For interference module, the systematics are wrong.
  3204.         # automatically set use_syst=F and set systematics_program=none
  3205.         no_systematics = False
  3206.         for proc in proc_def:
  3207.             for oneproc in proc:
  3208.                 if '^2' in oneproc.nice_string():
  3209.                     no_systematics = True
  3210.                     break
  3211.             else:
  3212.                 continue
  3213.             break
  3214.         if no_systematics:
  3215.             self['use_syst'] = False
  3216.             self['systematics_program'] = 'none'
  3217.            
  3218.     def write(self, output_file, template=None, python_template=False,
  3219.               **opt):
  3220.         """Write the run_card in output_file according to template
  3221.           (a path to a valid run_card)"""
  3222.  
  3223.         if not template:
  3224.             if not MADEVENT:
  3225.                 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
  3226.                                                         'run_card.dat')
  3227.                 python_template = True
  3228.             else:
  3229.                 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
  3230.                 python_template = False
  3231.        
  3232.         super(RunCardLO, self).write(output_file, template=template,
  3233.                                     python_template=python_template, **opt)            
  3234.  
  3235.  
  3236. class InvalidMadAnalysis5Card(InvalidCmd):
  3237.     pass
  3238.  
  3239. class MadAnalysis5Card(dict):
  3240.     """ A class to store a MadAnalysis5 card. Very basic since it is basically
  3241.    free format."""
  3242.    
  3243.     _MG5aMC_escape_tag = '@MG5aMC'
  3244.    
  3245.     _default_hadron_inputs = ['*.hepmc', '*.hep', '*.stdhep', '*.lhco','*.root']
  3246.     _default_parton_inputs = ['*.lhe']
  3247.     _skip_analysis         = False
  3248.    
  3249.     @classmethod
  3250.     def events_can_be_reconstructed(cls, file_path):
  3251.         """ Checks from the type of an event file whether it can be reconstructed or not."""
  3252.         return not (file_path.endswith('.lhco') or file_path.endswith('.lhco.gz') or \
  3253.                           file_path.endswith('.root') or file_path.endswith('.root.gz'))
  3254.    
  3255.     @classmethod
  3256.     def empty_analysis(cls):
  3257.         """ A method returning the structure of an empty analysis """
  3258.         return {'commands':[],
  3259.                 'reconstructions':[]}
  3260.  
  3261.     @classmethod
  3262.     def empty_reconstruction(cls):
  3263.         """ A method returning the structure of an empty reconstruction """
  3264.         return {'commands':[],
  3265.                 'reco_output':'lhe'}
  3266.  
  3267.     def default_setup(self):
  3268.         """define the default value"""
  3269.         self['mode']      = 'parton'
  3270.         self['inputs']    = []
  3271.         # None is the default stdout level, it will be set automatically by MG5aMC
  3272.         self['stdout_lvl'] = None
  3273.         # These two dictionaries are formated as follows:
  3274.         #     {'analysis_name':
  3275.         #          {'reconstructions' : ['associated_reconstructions_name']}
  3276.         #          {'commands':['analysis command lines here']}    }
  3277.         # with values being of the form of the empty_analysis() attribute
  3278.         # of this class and some other property could be added to this dictionary
  3279.         # in the future.
  3280.         self['analyses']       = {}
  3281.         # The recasting structure contains on set of commands and one set of
  3282.         # card lines.
  3283.         self['recasting']      = {'commands':[],'card':[]}
  3284.         # Add the default trivial reconstruction to use an lhco input
  3285.         # This is just for the structure
  3286.         self['reconstruction'] = {'lhco_input':
  3287.                                         MadAnalysis5Card.empty_reconstruction(),
  3288.                                   'root_input':
  3289.                                         MadAnalysis5Card.empty_reconstruction()}
  3290.         self['reconstruction']['lhco_input']['reco_output']='lhco'
  3291.         self['reconstruction']['root_input']['reco_output']='root'        
  3292.  
  3293.         # Specify in which order the analysis/recasting were specified
  3294.         self['order'] = []
  3295.  
  3296.     def __init__(self, finput=None,mode=None):
  3297.         if isinstance(finput, self.__class__):
  3298.             dict.__init__(self, finput)
  3299.             assert finput.__dict__.keys()
  3300.             for key in finput.__dict__:
  3301.                 setattr(self, key, copy.copy(getattr(finput, key)) )
  3302.             return
  3303.         else:
  3304.             dict.__init__(self)
  3305.        
  3306.         # Initialize it with all the default value
  3307.         self.default_setup()
  3308.         if not mode is None:
  3309.             self['mode']=mode
  3310.  
  3311.         # if input is define read that input
  3312.         if isinstance(finput, (file, str, StringIO.StringIO)):
  3313.             self.read(finput, mode=mode)
  3314.    
  3315.     def read(self, input, mode=None):
  3316.         """ Read an MA5 card"""
  3317.        
  3318.         if mode not in [None,'parton','hadron']:
  3319.             raise MadGraph5Error('A MadAnalysis5Card can be read online the modes'+
  3320.                                                          "'parton' or 'hadron'")
  3321.         card_mode = mode
  3322.        
  3323.         if isinstance(input, (file, StringIO.StringIO)):
  3324.             input_stream = input
  3325.         elif isinstance(input, str):
  3326.             if not os.path.isfile(input):
  3327.                 raise InvalidMadAnalysis5Card("Cannot read the MadAnalysis5 card."+\
  3328.                                                     "File '%s' not found."%input)
  3329.             if mode is None and 'hadron' in input:
  3330.                 card_mode = 'hadron'
  3331.             input_stream = open(input,'r')
  3332.         else:
  3333.             raise MadGraph5Error('Incorrect input for the read function of'+\
  3334.               ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(input)))
  3335.  
  3336.         # Reinstate default values
  3337.         self.__init__()
  3338.         current_name = 'default'
  3339.         current_type = 'analyses'
  3340.         for line in input_stream:
  3341.             # Skip comments for now
  3342.             if line.startswith('#'):
  3343.                 continue
  3344.             if line.endswith('\n'):
  3345.                 line = line[:-1]
  3346.             if line.strip()=='':
  3347.                 continue
  3348.             if line.startswith(self._MG5aMC_escape_tag):
  3349.                 try:
  3350.                     option,value = line[len(self._MG5aMC_escape_tag):].split('=')
  3351.                     value = value.strip()
  3352.                 except ValueError:
  3353.                     option = line[len(self._MG5aMC_escape_tag):]
  3354.                 option = option.strip()
  3355.                
  3356.                 if option=='inputs':
  3357.                     self['inputs'].extend([v.strip() for v in value.split(',')])
  3358.                
  3359.                 elif option == 'skip_analysis':
  3360.                     self._skip_analysis = True
  3361.  
  3362.                 elif option=='stdout_lvl':
  3363.                     try: # It is likely an int
  3364.                         self['stdout_lvl']=int(value)
  3365.                     except ValueError:
  3366.                         try: # Maybe the user used something like 'logging.INFO'
  3367.                             self['stdout_lvl']=eval(value)
  3368.                         except:
  3369.                             try:
  3370.                                self['stdout_lvl']=eval('logging.%s'%value)
  3371.                             except:
  3372.                                 raise InvalidMadAnalysis5Card(
  3373.                  "MA5 output level specification '%s' is incorrect."%str(value))
  3374.                
  3375.                 elif option=='analysis_name':
  3376.                     current_type = 'analyses'
  3377.                     current_name = value
  3378.                     if current_name in self[current_type]:
  3379.                         raise InvalidMadAnalysis5Card(
  3380.                "Analysis '%s' already defined in MadAnalysis5 card"%current_name)
  3381.                     else:
  3382.                         self[current_type][current_name] = MadAnalysis5Card.empty_analysis()
  3383.                
  3384.                 elif option=='set_reconstructions':
  3385.                     try:
  3386.                         reconstructions = eval(value)
  3387.                         if not isinstance(reconstructions, list):
  3388.                             raise
  3389.                     except:
  3390.                         raise InvalidMadAnalysis5Card("List of reconstructions"+\
  3391.                          " '%s' could not be parsed in MadAnalysis5 card."%value)
  3392.                     if current_type!='analyses' and current_name not in self[current_type]:
  3393.                         raise InvalidMadAnalysis5Card("A list of reconstructions"+\
  3394.                                    "can only be defined in the context of an "+\
  3395.                                              "analysis in a MadAnalysis5 card.")
  3396.                     self[current_type][current_name]['reconstructions']=reconstructions
  3397.                     continue
  3398.                
  3399.                 elif option=='reconstruction_name':
  3400.                     current_type = 'reconstruction'
  3401.                     current_name = value
  3402.                     if current_name in self[current_type]:
  3403.                         raise InvalidMadAnalysis5Card(
  3404.                "Reconstruction '%s' already defined in MadAnalysis5 hadron card"%current_name)
  3405.                     else:
  3406.                         self[current_type][current_name] = MadAnalysis5Card.empty_reconstruction()
  3407.  
  3408.                 elif option=='reco_output':
  3409.                     if current_type!='reconstruction' or current_name not in \
  3410.                                                          self['reconstruction']:
  3411.                         raise InvalidMadAnalysis5Card(
  3412.                "Option '%s' is only available within the definition of a reconstruction"%option)
  3413.                     if not value.lower() in ['lhe','root']:
  3414.                         raise InvalidMadAnalysis5Card(
  3415.                                   "Option '%s' can only take the values 'lhe' or 'root'"%option)
  3416.                     self['reconstruction'][current_name]['reco_output'] = value.lower()
  3417.                
  3418.                 elif option.startswith('recasting'):
  3419.                     current_type = 'recasting'
  3420.                     try:
  3421.                         current_name = option.split('_')[1]
  3422.                     except:
  3423.                         raise InvalidMadAnalysis5Card('Malformed MA5 recasting option %s.'%option)
  3424.                     if len(self['recasting'][current_name])>0:
  3425.                         raise InvalidMadAnalysis5Card(
  3426.                "Only one recasting can be defined in MadAnalysis5 hadron card")
  3427.                
  3428.                 else:
  3429.                     raise InvalidMadAnalysis5Card(
  3430.                "Unreckognized MG5aMC instruction in MadAnalysis5 card: '%s'"%option)
  3431.                
  3432.                 if option in ['analysis_name','reconstruction_name'] or \
  3433.                                                  option.startswith('recasting'):
  3434.                     self['order'].append((current_type,current_name))
  3435.                 continue
  3436.  
  3437.             # Add the default analysis if needed since the user does not need
  3438.             # to specify it.
  3439.             if current_name == 'default' and current_type == 'analyses' and\
  3440.                                           'default' not in self['analyses']:
  3441.                     self['analyses']['default'] = MadAnalysis5Card.empty_analysis()
  3442.                     self['order'].append(('analyses','default'))
  3443.  
  3444.             if current_type in ['recasting']:
  3445.                 self[current_type][current_name].append(line)
  3446.             elif current_type in ['reconstruction']:
  3447.                 self[current_type][current_name]['commands'].append(line)
  3448.             elif current_type in ['analyses']:
  3449.                 self[current_type][current_name]['commands'].append(line)
  3450.  
  3451.         if 'reconstruction' in self['analyses'] or len(self['recasting']['card'])>0:
  3452.             if mode=='parton':
  3453.                 raise InvalidMadAnalysis5Card(
  3454.       "A parton MadAnalysis5 card cannot specify a recombination or recasting.")
  3455.             card_mode = 'hadron'
  3456.         elif mode is None:
  3457.             card_mode = 'parton'
  3458.  
  3459.         self['mode'] = card_mode
  3460.         if self['inputs'] == []:
  3461.             if self['mode']=='hadron':
  3462.                 self['inputs']  = self._default_hadron_inputs
  3463.             else:
  3464.                 self['inputs']  = self._default_parton_inputs
  3465.        
  3466.         # Make sure at least one reconstruction is specified for each hadron
  3467.         # level analysis and that it exists.
  3468.         if self['mode']=='hadron':
  3469.             for analysis_name, analysis in self['analyses'].items():
  3470.                 if len(analysis['reconstructions'])==0:
  3471.                     raise InvalidMadAnalysis5Card('Hadron-level analysis '+\
  3472.                       "'%s' is not specified any reconstruction(s)."%analysis_name)
  3473.                 if any(reco not in self['reconstruction'] for reco in \
  3474.                                                    analysis['reconstructions']):
  3475.                     raise InvalidMadAnalysis5Card('A reconstructions specified in'+\
  3476.                                  " analysis '%s' is not defined."%analysis_name)
  3477.    
  3478.     def write(self, output):
  3479.         """ Write an MA5 card."""
  3480.  
  3481.         if isinstance(output, (file, StringIO.StringIO)):
  3482.             output_stream = output
  3483.         elif isinstance(output, str):
  3484.             output_stream = open(output,'w')
  3485.         else:
  3486.             raise MadGraph5Error('Incorrect input for the write function of'+\
  3487.               ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(output)))
  3488.        
  3489.         output_lines = []
  3490.         if self._skip_analysis:
  3491.             output_lines.append('%s skip_analysis'%self._MG5aMC_escape_tag)
  3492.         output_lines.append('%s inputs = %s'%(self._MG5aMC_escape_tag,','.join(self['inputs'])))
  3493.         if not self['stdout_lvl'] is None:
  3494.             output_lines.append('%s stdout_lvl=%s'%(self._MG5aMC_escape_tag,self['stdout_lvl']))
  3495.         for definition_type, name in self['order']:
  3496.            
  3497.             if definition_type=='analyses':
  3498.                 output_lines.append('%s analysis_name = %s'%(self._MG5aMC_escape_tag,name))
  3499.                 output_lines.append('%s set_reconstructions = %s'%(self._MG5aMC_escape_tag,
  3500.                                 str(self['analyses'][name]['reconstructions'])))                
  3501.             elif definition_type=='reconstruction':
  3502.                 output_lines.append('%s reconstruction_name = %s'%(self._MG5aMC_escape_tag,name))
  3503.             elif definition_type=='recasting':
  3504.                 output_lines.append('%s recasting_%s'%(self._MG5aMC_escape_tag,name))
  3505.  
  3506.             if definition_type in ['recasting']:
  3507.                 output_lines.extend(self[definition_type][name])
  3508.             elif definition_type in ['reconstruction']:
  3509.                 output_lines.append('%s reco_output = %s'%(self._MG5aMC_escape_tag,
  3510.                                     self[definition_type][name]['reco_output']))                
  3511.                 output_lines.extend(self[definition_type][name]['commands'])
  3512.             elif definition_type in ['analyses']:
  3513.                 output_lines.extend(self[definition_type][name]['commands'])                
  3514.        
  3515.         output_stream.write('\n'.join(output_lines))
  3516.        
  3517.         return
  3518.    
  3519.     def get_MA5_cmds(self, inputs_arg, submit_folder, run_dir_path=None,
  3520.                                                UFO_model_path=None, run_tag=''):
  3521.         """ Returns a list of tuples ('AnalysisTag',['commands']) specifying
  3522.        the commands of the MadAnalysis runs required from this card.
  3523.        At parton-level, the number of such commands is the number of analysis
  3524.        asked for. In the future, the idea is that the entire card can be
  3525.        processed in one go from MA5 directly."""
  3526.        
  3527.         if isinstance(inputs_arg, list):
  3528.             inputs = inputs_arg
  3529.         elif isinstance(inputs_arg, str):
  3530.             inputs = [inputs_arg]
  3531.         else:
  3532.             raise MadGraph5Error("The function 'get_MA5_cmds' can only take "+\
  3533.                             " a string or a list for the argument 'inputs_arg'")
  3534.        
  3535.         if len(inputs)==0:
  3536.             raise MadGraph5Error("The function 'get_MA5_cmds' must have "+\
  3537.                                               " at least one input specified'")
  3538.        
  3539.         if run_dir_path is None:
  3540.             run_dir_path = os.path.dirname(inputs_arg)
  3541.        
  3542.         cmds_list = []
  3543.        
  3544.         UFO_load = []
  3545.         # first import the UFO if provided
  3546.         if UFO_model_path:
  3547.             UFO_load.append('import %s'%UFO_model_path)
  3548.        
  3549.         def get_import(input, type=None):
  3550.             """ Generates the MA5 import commands for that event file. """
  3551.             dataset_name = os.path.basename(input).split('.')[0]
  3552.             res = ['import %s as %s'%(input, dataset_name)]
  3553.             if not type is None:
  3554.                 res.append('set %s.type = %s'%(dataset_name, type))
  3555.             return res
  3556.        
  3557.         fifo_status = {'warned_fifo':False,'fifo_used_up':False}
  3558.         def warn_fifo(input):
  3559.             if not input.endswith('.fifo'):
  3560.                 return False
  3561.             if not fifo_status['fifo_used_up']:
  3562.                 fifo_status['fifo_used_up'] = True
  3563.                 return False
  3564.             else:
  3565.                 if not fifo_status['warned_fifo']:
  3566.                     logger.warning('Only the first MA5 analysis/reconstructions can be run on a fifo. Subsequent runs will skip fifo inputs.')
  3567.                     fifo_status['warned_fifo'] = True
  3568.                 return True
  3569.            
  3570.         # Then the event file(s) input(s)
  3571.         inputs_load = []
  3572.         for input in inputs:
  3573.             inputs_load.extend(get_import(input))
  3574.        
  3575.         submit_command = 'submit %s'%submit_folder+'_%s'
  3576.        
  3577.         # Keep track of the reconstruction outpus in the MA5 workflow
  3578.         # Keys are reconstruction names and values are .lhe.gz reco file paths.
  3579.         # We put by default already the lhco/root ones present
  3580.         reconstruction_outputs = {
  3581.                 'lhco_input':[f for f in inputs if
  3582.                                  f.endswith('.lhco') or f.endswith('.lhco.gz')],
  3583.                 'root_input':[f for f in inputs if
  3584.                                  f.endswith('.root') or f.endswith('.root.gz')]}
  3585.  
  3586.         # If a recasting card has to be written out, chose here its path
  3587.         recasting_card_path = pjoin(run_dir_path,
  3588.        '_'.join([run_tag,os.path.basename(submit_folder),'recasting_card.dat']))
  3589.  
  3590.         # Make sure to only run over one analysis over each fifo.
  3591.         for definition_type, name in self['order']:
  3592.             if definition_type == 'reconstruction':  
  3593.                 analysis_cmds = list(self['reconstruction'][name]['commands'])
  3594.                 reco_outputs = []
  3595.                 for i_input, input in enumerate(inputs):
  3596.                     # Skip lhco/root as they must not be reconstructed
  3597.                     if not MadAnalysis5Card.events_can_be_reconstructed(input):
  3598.                         continue
  3599.                     # Make sure the input is not a used up fifo.
  3600.                     if warn_fifo(input):
  3601.                         continue
  3602.                     analysis_cmds.append('import %s as reco_events'%input)
  3603.                     if self['reconstruction'][name]['reco_output']=='lhe':
  3604.                         reco_outputs.append('%s_%s.lhe.gz'%(os.path.basename(
  3605.                                input).replace('_events','').split('.')[0],name))
  3606.                         analysis_cmds.append('set main.outputfile=%s'%reco_outputs[-1])
  3607.                     elif self['reconstruction'][name]['reco_output']=='root':
  3608.                         reco_outputs.append('%s_%s.root'%(os.path.basename(
  3609.                                input).replace('_events','').split('.')[0],name))
  3610.                         analysis_cmds.append('set main.fastsim.rootfile=%s'%reco_outputs[-1])
  3611.                     analysis_cmds.append(
  3612.                                  submit_command%('reco_%s_%d'%(name,i_input+1)))
  3613.                     analysis_cmds.append('remove reco_events')
  3614.                    
  3615.                 reconstruction_outputs[name]= [pjoin(run_dir_path,rec_out)
  3616.                                                     for rec_out in reco_outputs]
  3617.                 if len(reco_outputs)>0:
  3618.                     cmds_list.append(('_reco_%s'%name,analysis_cmds))
  3619.  
  3620.             elif definition_type == 'analyses':
  3621.                 if self['mode']=='parton':
  3622.                     cmds_list.append( (name, UFO_load+inputs_load+
  3623.                       self['analyses'][name]['commands']+[submit_command%name]) )
  3624.                 elif self['mode']=='hadron':
  3625.                     # Also run on the already reconstructed root/lhco files if found.
  3626.                     for reco in self['analyses'][name]['reconstructions']+\
  3627.                                                     ['lhco_input','root_input']:
  3628.                         if len(reconstruction_outputs[reco])==0:
  3629.                             continue
  3630.                         if self['reconstruction'][reco]['reco_output']=='lhe':
  3631.                             # For the reconstructed lhe output we must be in parton mode
  3632.                             analysis_cmds = ['set main.mode = parton']
  3633.                         else:
  3634.                             analysis_cmds = []
  3635.                         analysis_cmds.extend(sum([get_import(rec_out) for
  3636.                                    rec_out in reconstruction_outputs[reco]],[]))
  3637.                         analysis_cmds.extend(self['analyses'][name]['commands'])
  3638.                         analysis_cmds.append(submit_command%('%s_%s'%(name,reco)))
  3639.                         cmds_list.append( ('%s_%s'%(name,reco),analysis_cmds)  )
  3640.  
  3641.             elif definition_type == 'recasting':
  3642.                 if len(self['recasting']['card'])==0:
  3643.                     continue
  3644.                 if name == 'card':
  3645.                     # Create the card here
  3646.                     open(recasting_card_path,'w').write('\n'.join(self['recasting']['card']))
  3647.                 if name == 'commands':
  3648.                     recasting_cmds = list(self['recasting']['commands'])
  3649.                     # Exclude LHCO files here of course
  3650.                     n_inputs = 0
  3651.                     for input in inputs:
  3652.                         if not MadAnalysis5Card.events_can_be_reconstructed(input):
  3653.                             continue
  3654.                         # Make sure the input is not a used up fifo.
  3655.                         if warn_fifo(input):
  3656.                             continue
  3657.                         recasting_cmds.extend(get_import(input,'signal'))
  3658.                         n_inputs += 1
  3659.  
  3660.                     recasting_cmds.append('set main.recast.card_path=%s'%recasting_card_path)
  3661.                     recasting_cmds.append(submit_command%'Recasting')
  3662.                     if n_inputs>0:
  3663.                         cmds_list.append( ('Recasting',recasting_cmds))
  3664.  
  3665.         return cmds_list
  3666.  
  3667. class RunCardNLO(RunCard):
  3668.     """A class object for the run_card for a (aMC@)NLO pocess"""
  3669.    
  3670.     def default_setup(self):
  3671.         """define the default value"""
  3672.        
  3673.         self.add_param('run_tag', 'tag_1', include=False)
  3674.         self.add_param('nevents', 10000)
  3675.         self.add_param('req_acc', -1.0, include=False)
  3676.         self.add_param('nevt_job', -1, include=False)
  3677.         self.add_param('event_norm', 'average')
  3678.         #FO parameter
  3679.         self.add_param('req_acc_fo', 0.01, include=False)        
  3680.         self.add_param('npoints_fo_grid', 5000, include=False)
  3681.         self.add_param('niters_fo_grid', 4, include=False)
  3682.         self.add_param('npoints_fo', 10000, include=False)        
  3683.         self.add_param('niters_fo', 6, include=False)
  3684.         #seed and collider
  3685.         self.add_param('iseed', 0)
  3686.         self.add_param('lpp1', 1, fortran_name='lpp(1)')        
  3687.         self.add_param('lpp2', 1, fortran_name='lpp(2)')                        
  3688.         self.add_param('ebeam1', 6500.0, fortran_name='ebeam(1)')
  3689.         self.add_param('ebeam2', 6500.0, fortran_name='ebeam(2)')        
  3690.         self.add_param('pdlabel', 'nn23nlo', allowed=['lhapdf', 'cteq6_m','cteq6_d','cteq6_l','cteq6l1', 'nn23lo','nn23lo1','nn23nlo'])                
  3691.         self.add_param('lhaid', [244600],fortran_name='lhaPDFid')
  3692.         self.add_param('lhapdfsetname', ['internal_use_only'], system=True)
  3693.         #shower and scale
  3694.         self.add_param('parton_shower', 'HERWIG6', fortran_name='shower_mc')        
  3695.         self.add_param('shower_scale_factor',1.0)
  3696.         self.add_param('fixed_ren_scale', False)
  3697.         self.add_param('fixed_fac_scale', False)
  3698.         self.add_param('mur_ref_fixed', 91.118)                      
  3699.         self.add_param('muf1_ref_fixed', -1.0, hidden=True)
  3700.         self.add_param('muf_ref_fixed', 91.118)                      
  3701.         self.add_param('muf2_ref_fixed', -1.0, hidden=True)
  3702.         self.add_param("dynamical_scale_choice", [-1],fortran_name='dyn_scale', comment="\'-1\' is based on CKKW back clustering (following feynman diagram).\n \'1\' is the sum of transverse energy.\n '2' is HT (sum of the transverse mass)\n '3' is HT/2")
  3703.         self.add_param('fixed_qes_scale', False, hidden=True)
  3704.         self.add_param('qes_ref_fixed', -1.0, hidden=True)
  3705.         self.add_param('mur_over_ref', 1.0)
  3706.         self.add_param('muf_over_ref', 1.0)                      
  3707.         self.add_param('muf1_over_ref', -1.0, hidden=True)                      
  3708.         self.add_param('muf2_over_ref', -1.0, hidden=True)
  3709.         self.add_param('qes_over_ref', -1.0, hidden=True)
  3710.         self.add_param('reweight_scale', [True], fortran_name='lscalevar')
  3711.         self.add_param('rw_rscale_down', -1.0, hidden=True)        
  3712.         self.add_param('rw_rscale_up', -1.0, hidden=True)
  3713.         self.add_param('rw_fscale_down', -1.0, hidden=True)                      
  3714.         self.add_param('rw_fscale_up', -1.0, hidden=True)
  3715.         self.add_param('rw_rscale', [1.0,2.0,0.5], fortran_name='scalevarR')
  3716.         self.add_param('rw_fscale', [1.0,2.0,0.5], fortran_name='scalevarF')
  3717.         self.add_param('reweight_pdf', [False], fortran_name='lpdfvar')
  3718.         self.add_param('pdf_set_min', 244601, hidden=True)
  3719.         self.add_param('pdf_set_max', 244700, hidden=True)
  3720.         self.add_param('store_rwgt_info', False)
  3721.         self.add_param('systematics_program', 'none', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics')
  3722.         self.add_param('systematics_arguments', [''], include=False, hidden=True, comment='Choose the argment to pass to the systematics command. like --mur=0.25,1,4. Look at the help of the systematics function for more details.')
  3723.              
  3724.         #merging
  3725.         self.add_param('ickkw', 0)
  3726.         self.add_param('bwcutoff', 15.0)
  3727.         #cuts        
  3728.         self.add_param('jetalgo', 1.0)
  3729.         self.add_param('jetradius', 0.7)        
  3730.         self.add_param('ptj', 10.0 , cut=True)
  3731.         self.add_param('etaj', -1.0, cut=True)        
  3732.         self.add_param('ptl', 0.0, cut=True)
  3733.         self.add_param('etal', -1.0, cut=True)
  3734.         self.add_param('drll', 0.0, cut=True)
  3735.         self.add_param('drll_sf', 0.0, cut=True)        
  3736.         self.add_param('mll', 0.0, cut=True)
  3737.         self.add_param('mll_sf', 30.0, cut=True)
  3738.         self.add_param('ptgmin', 20.0, cut=True)
  3739.         self.add_param('etagamma', -1.0)        
  3740.         self.add_param('r0gamma', 0.4)
  3741.         self.add_param('xn', 1.0)                        
  3742.         self.add_param('epsgamma', 1.0)
  3743.         self.add_param('isoem', True)        
  3744.         self.add_param('maxjetflavor', 4, hidden=True)
  3745.         self.add_param('iappl', 0)  
  3746.         self.add_param('lhe_version', 3, hidden=True, include=False)
  3747.        
  3748.         #internal variable related to FO_analyse_card
  3749.         self.add_param('FO_LHE_weight_ratio',1e-3, hidden=True, system=True)
  3750.         self.add_param('FO_LHE_postprocessing',['grouping','random'],
  3751.                        hidden=True, system=True, include=False)
  3752.    
  3753.         # parameter allowing to define simple cut via the pdg
  3754.         self.add_param('pt_min_pdg',{'__type__':0.}, include=False)
  3755.         self.add_param('pt_max_pdg',{'__type__':0.}, include=False)
  3756.         self.add_param('mxx_min_pdg',{'__type__':0.}, include=False)
  3757.         self.add_param('mxx_only_part_antipart', {'default':False}, include=False, hidden=True)
  3758.        
  3759.         #hidden parameter that are transfer to the fortran code
  3760.         self.add_param('pdg_cut',[0], hidden=True, system=True) # store which PDG are tracked
  3761.         self.add_param('ptmin4pdg',[0.], hidden=True, system=True) # store pt min
  3762.         self.add_param('ptmax4pdg',[-1.], hidden=True, system=True)
  3763.         self.add_param('mxxmin4pdg',[0.], hidden=True, system=True)
  3764.         self.add_param('mxxpart_antipart', [False], hidden=True, system=True)
  3765.        
  3766.     def check_validity(self):
  3767.         """check the validity of the various input"""
  3768.        
  3769.         super(RunCardNLO, self).check_validity()
  3770.  
  3771.         # for lepton-lepton collisions, ignore 'pdlabel' and 'lhaid'
  3772.         if self['lpp1']==0 and self['lpp2']==0:
  3773.             if self['pdlabel']!='nn23nlo' or self['reweight_pdf']:
  3774.                 self['pdlabel']='nn23nlo'
  3775.                 self['reweight_pdf']=[False]
  3776.                 logger.info('''Lepton-lepton collisions: ignoring PDF related parameters in the run_card.dat (pdlabel, lhaid, reweight_pdf, ...)''')
  3777.        
  3778.         # For FxFx merging, make sure that the following parameters are set correctly:
  3779.         if self['ickkw'] == 3:
  3780.             # 1. Renormalization and factorization (and ellis-sexton scales) are not fixed      
  3781.             scales=['fixed_ren_scale','fixed_fac_scale','fixed_QES_scale']
  3782.             for scale in scales:
  3783.                 if self[scale]:
  3784.                     logger.warning('''For consistency in the FxFx merging, \'%s\' has been set to false'''
  3785.                                 % scale,'$MG:BOLD')
  3786.                     self[scale]= False
  3787.             #and left to default dynamical scale
  3788.             if len(self["dynamical_scale_choice"]) > 1 or self["dynamical_scale_choice"][0] != -1:
  3789.                 self["dynamical_scale_choice"] = [-1]
  3790.                 self["reweight_scale"]=[self["reweight_scale"][0]]
  3791.                 logger.warning('''For consistency in the FxFx merging, dynamical_scale_choice has been set to -1 (default)'''
  3792.                                 ,'$MG:BOLD')
  3793.                
  3794.             # 2. Use kT algorithm for jets with pseudo-code size R=1.0
  3795.             jetparams=['jetradius','jetalgo']
  3796.             for jetparam in jetparams:
  3797.                 if float(self[jetparam]) != 1.0:
  3798.                     logger.info('''For consistency in the FxFx merging, \'%s\' has been set to 1.0'''
  3799.                                 % jetparam ,'$MG:BOLD')
  3800.                     self[jetparam] = 1.0
  3801.         elif self['ickkw'] == -1 and (self["dynamical_scale_choice"][0] != -1 or
  3802.                                       len(self["dynamical_scale_choice"]) > 1):
  3803.                 self["dynamical_scale_choice"] = [-1]
  3804.                 self["reweight_scale"]=[self["reweight_scale"][0]]
  3805.                 logger.warning('''For consistency with the jet veto, the scale which will be used is ptj. dynamical_scale_choice will be set at -1.'''
  3806.                                 ,'$MG:BOLD')            
  3807.                                
  3808.         # For interface to APPLGRID, need to use LHAPDF and reweighting to get scale uncertainties
  3809.         if self['iappl'] != 0 and self['pdlabel'].lower() != 'lhapdf':
  3810.             raise InvalidRunCard('APPLgrid generation only possible with the use of LHAPDF')
  3811.         if self['iappl'] != 0 and not self['reweight_scale']:
  3812.             raise InvalidRunCard('APPLgrid generation only possible with including' +\
  3813.                                       ' the reweighting to get scale dependence')
  3814.  
  3815.         # Hidden values check
  3816.         if self['qes_ref_fixed'] == -1.0:
  3817.             self['qes_ref_fixed']=self['mur_ref_fixed']
  3818.         if self['qes_over_ref'] == -1.0:
  3819.             self['qes_over_ref']=self['mur_over_ref']
  3820.         if self['muf1_over_ref'] != -1.0 and self['muf1_over_ref'] == self['muf2_over_ref']:
  3821.             self['muf_over_ref']=self['muf1_over_ref']
  3822.         if self['muf1_over_ref'] == -1.0:
  3823.             self['muf1_over_ref']=self['muf_over_ref']
  3824.         if self['muf2_over_ref'] == -1.0:
  3825.             self['muf2_over_ref']=self['muf_over_ref']
  3826.         if self['muf1_ref_fixed'] != -1.0 and self['muf1_ref_fixed'] == self['muf2_ref_fixed']:
  3827.             self['muf_ref_fixed']=self['muf1_ref_fixed']
  3828.         if self['muf1_ref_fixed'] == -1.0:
  3829.             self['muf1_ref_fixed']=self['muf_ref_fixed']
  3830.         if self['muf2_ref_fixed'] == -1.0:
  3831.             self['muf2_ref_fixed']=self['muf_ref_fixed']
  3832.         # overwrite rw_rscale and rw_fscale when rw_(r/f)scale_(down/up) are explicitly given in the run_card for backward compatibility.
  3833.         if (self['rw_rscale_down'] != -1.0 and ['rw_rscale_down'] not in self['rw_rscale']) or\
  3834.            (self['rw_rscale_up'] != -1.0 and ['rw_rscale_up'] not in self['rw_rscale']):
  3835.             self['rw_rscale']=[1.0,self['rw_rscale_up'],self['rw_rscale_down']]
  3836.         if (self['rw_fscale_down'] != -1.0 and ['rw_fscale_down'] not in self['rw_fscale']) or\
  3837.            (self['rw_fscale_up'] != -1.0 and ['rw_fscale_up'] not in self['rw_fscale']):
  3838.             self['rw_fscale']=[1.0,self['rw_fscale_up'],self['rw_fscale_down']]
  3839.    
  3840.         # PDF reweighting check
  3841.         if any(self['reweight_pdf']):
  3842.             # check that we use lhapdf if reweighting is ON
  3843.             if self['pdlabel'] != "lhapdf":
  3844.                 raise InvalidRunCard, 'Reweight PDF option requires to use pdf sets associated to lhapdf. Please either change the pdlabel to use LHAPDF or set reweight_pdf to False.'
  3845.  
  3846.         # make sure set have reweight_pdf and lhaid of length 1 when not including lhapdf
  3847.         if self['pdlabel'] != "lhapdf":
  3848.             self['reweight_pdf']=[self['reweight_pdf'][0]]
  3849.             self['lhaid']=[self['lhaid'][0]]
  3850.            
  3851.         # make sure set have reweight_scale and dyn_scale_choice of length 1 when fixed scales:
  3852.         if self['fixed_ren_scale'] and self['fixed_fac_scale']:
  3853.             self['reweight_scale']=[self['reweight_scale'][0]]
  3854.             self['dynamical_scale_choice']=[0]
  3855.  
  3856.         # If there is only one reweight_pdf/reweight_scale, but
  3857.         # lhaid/dynamical_scale_choice are longer, expand the
  3858.         # reweight_pdf/reweight_scale list to have the same length
  3859.         if len(self['reweight_pdf']) == 1 and len(self['lhaid']) != 1:
  3860.             self['reweight_pdf']=self['reweight_pdf']*len(self['lhaid'])
  3861.             logger.warning("Setting 'reweight_pdf' for all 'lhaid' to %s" % self['reweight_pdf'][0])
  3862.         if len(self['reweight_scale']) == 1 and len(self['dynamical_scale_choice']) != 1:
  3863.             self['reweight_scale']=self['reweight_scale']*len(self['dynamical_scale_choice'])
  3864.             logger.warning("Setting 'reweight_scale' for all 'dynamical_scale_choice' to %s" % self['reweight_pdf'][0])
  3865.  
  3866.         # Check that there are no identical elements in lhaid or dynamical_scale_choice
  3867.         if len(self['lhaid']) != len(set(self['lhaid'])):
  3868.                 raise InvalidRunCard, "'lhaid' has two or more identical entries. They have to be all different for the code to work correctly."
  3869.         if len(self['dynamical_scale_choice']) != len(set(self['dynamical_scale_choice'])):
  3870.                 raise InvalidRunCard, "'dynamical_scale_choice' has two or more identical entries. They have to be all different for the code to work correctly."
  3871.            
  3872.         # Check that lenght of lists are consistent
  3873.         if len(self['reweight_pdf']) != len(self['lhaid']):
  3874.             raise InvalidRunCard, "'reweight_pdf' and 'lhaid' lists should have the same length"
  3875.         if len(self['reweight_scale']) != len(self['dynamical_scale_choice']):
  3876.             raise InvalidRunCard, "'reweight_scale' and 'dynamical_scale_choice' lists should have the same length"
  3877.         if len(self['dynamical_scale_choice']) > 10 :
  3878.             raise InvalidRunCard, "Length of list for 'dynamical_scale_choice' too long: max is 10."
  3879.         if len(self['lhaid']) > 25 :
  3880.             raise InvalidRunCard, "Length of list for 'lhaid' too long: max is 25."
  3881.         if len(self['rw_rscale']) > 9 :
  3882.             raise InvalidRunCard, "Length of list for 'rw_rscale' too long: max is 9."
  3883.         if len(self['rw_fscale']) > 9 :
  3884.             raise InvalidRunCard, "Length of list for 'rw_fscale' too long: max is 9."
  3885.     # make sure that the first element of rw_rscale and rw_fscale is the 1.0
  3886.         if 1.0 not in self['rw_rscale']:
  3887.             logger.warning("'1.0' has to be part of 'rw_rscale', adding it")
  3888.             self['rw_rscale'].insert(0,1.0)
  3889.         if 1.0 not in self['rw_fscale']:
  3890.             logger.warning("'1.0' has to be part of 'rw_fscale', adding it")
  3891.             self['rw_fscale'].insert(0,1.0)
  3892.         if self['rw_rscale'][0] != 1.0 and 1.0 in self['rw_rscale']:
  3893.             a=self['rw_rscale'].index(1.0)
  3894.             self['rw_rscale'][0],self['rw_rscale'][a]=self['rw_rscale'][a],self['rw_rscale'][0]
  3895.         if self['rw_fscale'][0] != 1.0 and 1.0 in self['rw_fscale']:
  3896.             a=self['rw_fscale'].index(1.0)
  3897.             self['rw_fscale'][0],self['rw_fscale'][a]=self['rw_fscale'][a],self['rw_fscale'][0]
  3898.     # check that all elements of rw_rscale and rw_fscale are diffent.
  3899.         if len(self['rw_rscale']) != len(set(self['rw_rscale'])):
  3900.                 raise InvalidRunCard, "'rw_rscale' has two or more identical entries. They have to be all different for the code to work correctly."
  3901.         if len(self['rw_fscale']) != len(set(self['rw_fscale'])):
  3902.                 raise InvalidRunCard, "'rw_fscale' has two or more identical entries. They have to be all different for the code to work correctly."
  3903.  
  3904.  
  3905.     def update_system_parameter_for_include(self):
  3906.        
  3907.         # set the pdg_for_cut fortran parameter
  3908.         pdg_to_cut = set(self['pt_min_pdg'].keys() +self['pt_max_pdg'].keys()+
  3909.                          self['mxx_min_pdg'].keys()+ self['mxx_only_part_antipart'].keys())
  3910.         pdg_to_cut.discard('__type__')
  3911.         pdg_to_cut.discard('default')
  3912.         if len(pdg_to_cut)>25:
  3913.             raise Exception, "Maximum 25 different PDGs are allowed for PDG specific cut"
  3914.        
  3915.         if any(int(pdg)<0 for pdg in pdg_to_cut):
  3916.             logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
  3917.             raise MadGraph5Error, 'Some PDG specific cuts are defined with negative PDG codes'
  3918.        
  3919.        
  3920.         if any(pdg in pdg_to_cut for pdg in [21,22,11,13,15]+ range(self['maxjetflavor']+1)):
  3921.             # Note that this will double check in the fortran code
  3922.             raise Exception, "Can not use PDG related cuts for massless SM particles/leptons"
  3923.         if pdg_to_cut:
  3924.             self['pdg_cut'] = list(pdg_to_cut)
  3925.             self['ptmin4pdg'] = []
  3926.             self['ptmax4pdg'] = []
  3927.             self['mxxmin4pdg'] = []
  3928.             self['mxxpart_antipart']  = []
  3929.             for pdg in self['pdg_cut']:
  3930.                 for var in ['pt','mxx']:
  3931.                     for minmax in ['min', 'max']:
  3932.                         if var == 'mxx' and minmax == 'max':
  3933.                             continue
  3934.                         new_var = '%s%s4pdg' % (var, minmax)
  3935.                         old_var = '%s_%s_pdg' % (var, minmax)
  3936.                         default = 0. if minmax=='min' else -1.
  3937.                         self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
  3938.                 #special for mxx_part_antipart
  3939.                 old_var = 'mxx_only_part_antipart'
  3940.                 new_var = 'mxxpart_antipart'
  3941.                 if 'default' in self[old_var]:
  3942.                     default = self[old_var]['default']
  3943.                     self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
  3944.                 else:
  3945.                     if str(pdg) not in self[old_var]:
  3946.                         raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
  3947.                     self[new_var].append(self[old_var][str(pdg)])
  3948.         else:
  3949.             self['pdg_cut'] = [0]
  3950.             self['ptmin4pdg'] = [0.]
  3951.             self['ptmax4pdg'] = [-1.]
  3952.             self['mxxmin4pdg'] = [0.]
  3953.             self['mxxpart_antipart'] = [False]
  3954.  
  3955.     def write(self, output_file, template=None, python_template=False, **opt):
  3956.         """Write the run_card in output_file according to template
  3957.           (a path to a valid run_card)"""
  3958.  
  3959.         if not template:
  3960.             if not MADEVENT:
  3961.                 template = pjoin(MG5DIR, 'Template', 'NLO', 'Cards',
  3962.                                                         'run_card.dat')
  3963.                 python_template = True
  3964.             else:
  3965.                 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
  3966.                 python_template = False
  3967.        
  3968.         super(RunCardNLO, self).write(output_file, template=template,
  3969.                                     python_template=python_template, **opt)
  3970.  
  3971.  
  3972.     def create_default_for_process(self, proc_characteristic, history, proc_def):
  3973.         """Rules
  3974.          e+ e- beam -> lpp:0 ebeam:500  
  3975.          p p beam -> set maxjetflavor automatically
  3976.        """
  3977.  
  3978.         # check for beam_id
  3979.         beam_id = set()
  3980.         for proc in proc_def:
  3981.             for leg in proc['legs']:
  3982.                 if not leg['state']:
  3983.                     beam_id.add(leg['id'])
  3984.         if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
  3985.             maxjetflavor = max([4]+[abs(i) for i in beam_id if  -7< i < 7])
  3986.             self['maxjetflavor'] = maxjetflavor
  3987.             pass
  3988.         elif 11 in beam_id or -11 in beam_id:
  3989.             self['lpp1'] = 0
  3990.             self['lpp2'] = 0
  3991.             self['ebeam1'] = 500
  3992.             self['ebeam2'] = 500
  3993.         else:
  3994.             self['lpp1'] = 0
  3995.             self['lpp2'] = 0  
  3996.            
  3997.         if proc_characteristic['ninitial'] == 1:
  3998.             #remove all cut
  3999.             self.remove_all_cut()
  4000.    
  4001.    
  4002.    
  4003. class MadLoopParam(ConfigFile):
  4004.     """ a class for storing/dealing with the file MadLoopParam.dat
  4005.    contains a parser to read it, facilities to write a new file,...
  4006.    """
  4007.    
  4008.     _ID_reduction_tool_map = {1:'CutTools',
  4009.                              2:'PJFry++',
  4010.                              3:'IREGI',
  4011.                              4:'Golem95',
  4012.                              5:'Samurai',
  4013.                              6:'Ninja',
  4014.                              7:'COLLIER'}
  4015.    
  4016.     def default_setup(self):
  4017.         """initialize the directory to the default value"""
  4018.        
  4019.         self.add_param("MLReductionLib", "6|7|1")
  4020.         self.add_param("IREGIMODE", 2)
  4021.         self.add_param("IREGIRECY", True)
  4022.         self.add_param("CTModeRun", -1)
  4023.         self.add_param("MLStabThres", 1e-3)
  4024.         self.add_param("NRotations_DP", 0)
  4025.         self.add_param("NRotations_QP", 0)
  4026.         self.add_param("ImprovePSPoint", 2)
  4027.         self.add_param("CTLoopLibrary", 2)
  4028.         self.add_param("CTStabThres", 1e-2)
  4029.         self.add_param("CTModeInit", 1)
  4030.         self.add_param("CheckCycle", 3)
  4031.         self.add_param("MaxAttempts", 10)
  4032.         self.add_param("ZeroThres", 1e-9)
  4033.         self.add_param("OSThres", 1.0e-8)
  4034.         self.add_param("DoubleCheckHelicityFilter", True)
  4035.         self.add_param("WriteOutFilters", True)
  4036.         self.add_param("UseLoopFilter", False)
  4037.         self.add_param("HelicityFilterLevel", 2)
  4038.         self.add_param("LoopInitStartOver", False)
  4039.         self.add_param("HelInitStartOver", False)
  4040.         self.add_param("UseQPIntegrandForNinja", True)        
  4041.         self.add_param("UseQPIntegrandForCutTools", True)
  4042.         self.add_param("COLLIERMode", 1)
  4043.         self.add_param("COLLIERComputeUVpoles", True)
  4044.         self.add_param("COLLIERComputeIRpoles", True)
  4045.         self.add_param("COLLIERRequiredAccuracy", 1.0e-8)
  4046.         self.add_param("COLLIERCanOutput",False)
  4047.         self.add_param("COLLIERGlobalCache",-1)
  4048.         self.add_param("COLLIERUseCacheForPoles",False)
  4049.         self.add_param("COLLIERUseInternalStabilityTest",True)
  4050.  
  4051.     def read(self, finput):
  4052.         """Read the input file, this can be a path to a file,
  4053.           a file object, a str with the content of the file."""
  4054.            
  4055.         if isinstance(finput, str):
  4056.             if "\n" in finput:
  4057.                 finput = finput.split('\n')
  4058.             elif os.path.isfile(finput):
  4059.                 finput = open(finput)
  4060.             else:
  4061.                 raise Exception, "No such file %s" % input
  4062.        
  4063.         previous_line= ''
  4064.         for line in finput:
  4065.             if previous_line.startswith('#'):
  4066.                 name = previous_line[1:].split()[0]
  4067.                 value = line.strip()
  4068.                 if len(value) and value[0] not in ['#', '!']:
  4069.                     self.__setitem__(name, value, change_userdefine=True)
  4070.             previous_line = line
  4071.        
  4072.    
  4073.     def write(self, outputpath, template=None,commentdefault=False):
  4074.        
  4075.         if not template:
  4076.             if not MADEVENT:
  4077.                 template = pjoin(MG5DIR, 'Template', 'loop_material', 'StandAlone',
  4078.                                                    'Cards', 'MadLoopParams.dat')
  4079.             else:
  4080.                 template = pjoin(MEDIR, 'Cards', 'MadLoopParams_default.dat')
  4081.         fsock = open(template, 'r')
  4082.         template = fsock.readlines()
  4083.         fsock.close()
  4084.        
  4085.         if isinstance(outputpath, str):
  4086.             output = open(outputpath, 'w')
  4087.         else:
  4088.             output = outputpath
  4089.  
  4090.         def f77format(value):
  4091.             if isinstance(value, bool):
  4092.                 if value:
  4093.                     return '.true.'
  4094.                 else:
  4095.                     return '.false.'
  4096.             elif isinstance(value, int):
  4097.                 return value
  4098.             elif isinstance(value, float):
  4099.                 tmp ='%e' % value
  4100.                 return tmp.replace('e','d')
  4101.             elif isinstance(value, str):
  4102.                 return value
  4103.             else:
  4104.                 raise Exception, "Can not format input %s" % type(value)
  4105.            
  4106.         name = ''
  4107.         done = set()
  4108.         for line in template:
  4109.             if name:
  4110.                 done.add(name)
  4111.                 if commentdefault and name.lower() not in self.user_set :
  4112.                     output.write('!%s\n' % f77format(self[name]))
  4113.                 else:
  4114.                     output.write('%s\n' % f77format(self[name]))
  4115.                 name=''
  4116.                 continue
  4117.             elif line.startswith('#'):
  4118.                 name = line[1:].split()[0]
  4119.             output.write(line)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement