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