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