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