Package madgraph :: Package various :: Module banner
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.banner

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