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 # We have a string we have to format the attribute from the string 1371 if targettype == UnknownType: 1372 # No formatting 1373 pass 1374 elif targettype == bool: 1375 value = value.strip() 1376 if value.lower() in ['0', '.false.', 'f', 'false', 'off']: 1377 value = False 1378 elif value.lower() in ['1', '.true.', 't', 'true', 'on']: 1379 value = True 1380 else: 1381 raise InvalidCmd("%s can not be mapped to True/False for %s" % (repr(value),name)) 1382 elif targettype == str: 1383 value = value.strip() 1384 if value.startswith('\'') and value.endswith('\''): 1385 value = value[1:-1] 1386 elif value.startswith('"') and value.endswith('"'): 1387 value = value[1:-1] 1388 elif targettype == int: 1389 if value.isdigit(): 1390 value = int(value) 1391 elif value[1:].isdigit() and value[0] == '-': 1392 value = int(value) 1393 elif value.endswith(('k', 'M')) and value[:-1].isdigit(): 1394 convert = {'k':1000, 'M':1000000} 1395 value =int(value[:-1]) * convert[value[-1]] 1396 elif '/' in value or '*' in value: 1397 try: 1398 split = re.split('(\*|/)',value) 1399 v = float(split[0]) 1400 for i in range((len(split)//2)): 1401 if split[2*i+1] == '*': 1402 v *= float(split[2*i+2]) 1403 else: 1404 v /= float(split[2*i+2]) 1405 except: 1406 v=0 1407 finally: 1408 value = int(v) 1409 if value != v: 1410 raise InvalidCmd( "%s can not be mapped to an integer" % v) 1411 else: 1412 try: 1413 value = float(value.replace('d','e')) 1414 except ValueError: 1415 raise InvalidCmd("%s can not be mapped to an integer" % value) 1416 try: 1417 new_value = int(value) 1418 except ValueError: 1419 raise InvalidCmd( "%s can not be mapped to an integer" % value) 1420 else: 1421 if value == new_value: 1422 value = new_value 1423 else: 1424 raise InvalidCmd("incorect input: %s need an integer for %s" % (value,name)) 1425 1426 elif targettype == float: 1427 if value.endswith(('k', 'M')) and value[:-1].isdigit(): 1428 convert = {'k':1000, 'M':1000000} 1429 value = 1.*int(value[:-1]) * convert[value[-1]] 1430 else: 1431 value = value.replace('d','e') # pass from Fortran formatting 1432 try: 1433 value = float(value) 1434 except ValueError: 1435 try: 1436 split = re.split('(\*|/)',value) 1437 v = float(split[0]) 1438 for i in range((len(split)//2)): 1439 if split[2*i+1] == '*': 1440 v *= float(split[2*i+2]) 1441 else: 1442 v /= float(split[2*i+2]) 1443 except: 1444 v=0 1445 raise InvalidCmd("%s can not be mapped to a float" % value) 1446 finally: 1447 value = v 1448 else: 1449 raise InvalidCmd("type %s is not handle by the card" % targettype) 1450 1451 return value
1452 1453 1454
1455 - def __getitem__(self, name):
1456 1457 lower_name = name.lower() 1458 if __debug__: 1459 if lower_name not in self: 1460 if lower_name in [key.lower() for key in self] : 1461 raise Exception("Some key are not lower case %s. Invalid use of the class!"\ 1462 % [key for key in self if key.lower() != key]) 1463 1464 if lower_name in self.auto_set: 1465 return 'auto' 1466 1467 return dict.__getitem__(self, name.lower())
1468 1469
1470 - def set(self, name, value, changeifuserset=True, user=False, raiseerror=False):
1471 """convenient way to change attribute. 1472 changeifuserset=False means that the value is NOT change is the value is not on default. 1473 user=True, means that the value will be marked as modified by the user 1474 (potentially preventing future change to the value) 1475 """ 1476 1477 # changeifuserset=False -> we need to check if the user force a value. 1478 if not changeifuserset: 1479 if name.lower() in self.user_set: 1480 #value modified by the user -> do nothing 1481 return 1482 1483 self.__setitem__(name, value, change_userdefine=user, raiseerror=raiseerror)
1484
1485 1486 1487 -class ProcCharacteristic(ConfigFile):
1488 """A class to handle information which are passed from MadGraph to the madevent 1489 interface.""" 1490
1491 - def default_setup(self):
1492 """initialize the directory to the default value""" 1493 1494 self.add_param('loop_induced', False) 1495 self.add_param('has_isr', False) 1496 self.add_param('has_fsr', False) 1497 self.add_param('nb_channel', 0) 1498 self.add_param('nexternal', 0) 1499 self.add_param('ninitial', 0) 1500 self.add_param('grouped_matrix', True) 1501 self.add_param('has_loops', False) 1502 self.add_param('bias_module','None') 1503 self.add_param('max_n_matched_jets', 0) 1504 self.add_param('colored_pdgs', [1,2,3,4,5]) 1505 self.add_param('complex_mass_scheme', False) 1506 self.add_param('pdg_initial1', [0]) 1507 self.add_param('pdg_initial2', [0]) 1508 self.add_param('splitting_types',[], typelist=str) 1509 self.add_param('perturbation_order', [], typelist=str) 1510 self.add_param('limitations', [], typelist=str) 1511 self.add_param('hel_recycling', False) 1512 self.add_param('single_color', True) 1513 self.add_param('nlo_mixed_expansion', True)
1514
1515 - def read(self, finput):
1516 """Read the input file, this can be a path to a file, 1517 a file object, a str with the content of the file.""" 1518 1519 if isinstance(finput, str): 1520 if "\n" in finput: 1521 finput = finput.split('\n') 1522 elif os.path.isfile(finput): 1523 finput = open(finput) 1524 else: 1525 raise Exception("No such file %s" % finput) 1526 1527 for line in finput: 1528 if '#' in line: 1529 line = line.split('#',1)[0] 1530 if not line: 1531 continue 1532 1533 if '=' in line: 1534 key, value = line.split('=',1) 1535 self[key.strip()] = value
1536
1537 - def write(self, outputpath):
1538 """write the file""" 1539 1540 template ="# Information about the process #\n" 1541 template +="#########################################\n" 1542 1543 fsock = open(outputpath, 'w') 1544 fsock.write(template) 1545 1546 for key, value in self.items(): 1547 fsock.write(" %s = %s \n" % (key, value)) 1548 1549 fsock.close()
1550
1551 1552 1553 1554 -class GridpackCard(ConfigFile):
1555 """an object for the GridpackCard""" 1556
1557 - def default_setup(self):
1558 """default value for the GridpackCard""" 1559 1560 self.add_param("GridRun", True) 1561 self.add_param("gevents", 2500) 1562 self.add_param("gseed", 1) 1563 self.add_param("ngran", -1)
1564
1565 - def read(self, finput):
1566 """Read the input file, this can be a path to a file, 1567 a file object, a str with the content of the file.""" 1568 1569 if isinstance(finput, str): 1570 if "\n" in finput: 1571 finput = finput.split('\n') 1572 elif os.path.isfile(finput): 1573 finput = open(finput) 1574 else: 1575 raise Exception("No such file %s" % finput) 1576 1577 for line in finput: 1578 line = line.split('#')[0] 1579 line = line.split('!')[0] 1580 line = line.split('=',1) 1581 if len(line) != 2: 1582 continue 1583 self[line[1].strip()] = line[0].replace('\'','').strip()
1584
1585 - def write(self, output_file, template=None):
1586 """Write the run_card in output_file according to template 1587 (a path to a valid run_card)""" 1588 1589 if not template: 1590 if not MADEVENT: 1591 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards', 1592 'grid_card_default.dat') 1593 else: 1594 template = pjoin(MEDIR, 'Cards', 'grid_card_default.dat') 1595 1596 1597 text = "" 1598 for line in open(template,'r'): 1599 nline = line.split('#')[0] 1600 nline = nline.split('!')[0] 1601 comment = line[len(nline):] 1602 nline = nline.split('=') 1603 if len(nline) != 2: 1604 text += line 1605 elif nline[1].strip() in self: 1606 text += ' %s\t= %s %s' % (self[nline[1].strip()],nline[1], comment) 1607 else: 1608 logger.info('Adding missing parameter %s to current run_card (with default value)' % nline[1].strip()) 1609 text += line 1610 1611 if isinstance(output_file, str): 1612 fsock = open(output_file,'w') 1613 else: 1614 fsock = output_file 1615 1616 fsock.write(text) 1617 fsock.close()
1618
1619 -class PY8Card(ConfigFile):
1620 """ Implements the Pythia8 card.""" 1621
1622 - def add_default_subruns(self, type):
1623 """ Placeholder function to allow overwriting in the PY8SubRun daughter. 1624 The initialization of the self.subruns attribute should of course not 1625 be performed in PY8SubRun.""" 1626 if type == 'parameters': 1627 if "LHEFInputs:nSubruns" not in self: 1628 self.add_param("LHEFInputs:nSubruns", 1, 1629 hidden='ALWAYS_WRITTEN', 1630 comment=""" 1631 ==================== 1632 Subrun definitions 1633 ==================== 1634 """) 1635 if type == 'attributes': 1636 if not(hasattr(self,'subruns')): 1637 first_subrun = PY8SubRun(subrun_id=0) 1638 self.subruns = dict([(first_subrun['Main:subrun'],first_subrun)])
1639
1640 - def default_setup(self):
1641 """ Sets up the list of available PY8 parameters.""" 1642 1643 # Visible parameters 1644 # ================== 1645 self.add_param("Main:numberOfEvents", -1) 1646 # for MLM merging 1647 # -1.0 means that it will be set automatically by MadGraph5_aMC@NLO 1648 self.add_param("JetMatching:qCut", -1.0, always_write_to_card=False) 1649 self.add_param("JetMatching:doShowerKt",False,always_write_to_card=False) 1650 # -1 means that it is automatically set. 1651 self.add_param("JetMatching:nJetMax", -1, always_write_to_card=False) 1652 # for CKKWL merging 1653 self.add_param("Merging:TMS", -1.0, always_write_to_card=False) 1654 self.add_param("Merging:Process", '<set_by_user>', always_write_to_card=False) 1655 # -1 means that it is automatically set. 1656 self.add_param("Merging:nJetMax", -1, always_write_to_card=False) 1657 # for both merging, chose whether to also consider different merging 1658 # scale values for the extra weights related to scale and PDF variations. 1659 self.add_param("SysCalc:fullCutVariation", False) 1660 # Select the HepMC output. The user can prepend 'fifo:<optional_fifo_path>' 1661 # to indicate that he wants to pipe the output. Or /dev/null to turn the 1662 # output off. 1663 self.add_param("HEPMCoutput:file", 'auto') 1664 1665 # Hidden parameters always written out 1666 # ==================================== 1667 self.add_param("Beams:frameType", 4, 1668 hidden=True, 1669 comment='Tell Pythia8 that an LHEF input is used.') 1670 self.add_param("HEPMCoutput:scaling", 1.0e9, 1671 hidden=True, 1672 comment='1.0 corresponds to HEPMC weight given in [mb]. We choose here the [pb] normalization.') 1673 self.add_param("Check:epTolErr", 1e-2, 1674 hidden=True, 1675 comment='Be more forgiving with momentum mismatches.') 1676 # By default it is important to disable any cut on the rapidity of the showered jets 1677 # during MLML merging and by default it is set to 2.5 1678 self.add_param("JetMatching:etaJetMax", 1000.0, hidden=True, always_write_to_card=True) 1679 1680 # Hidden parameters written out only if user_set or system_set 1681 # ============================================================ 1682 self.add_param("PDF:pSet", 'LHAPDF5:CT10.LHgrid', hidden=True, always_write_to_card=False, 1683 comment='Reminder: Parameter below is shower tune dependent.') 1684 self.add_param("SpaceShower:alphaSvalue", 0.118, hidden=True, always_write_to_card=False, 1685 comment='Reminder: Parameter below is shower tune dependent.') 1686 self.add_param("TimeShower:alphaSvalue", 0.118, hidden=True, always_write_to_card=False, 1687 comment='Reminder: Parameter below is shower tune dependent.') 1688 self.add_param("hadronlevel:all", True, hidden=True, always_write_to_card=False, 1689 comment='This allows to turn on/off hadronization alltogether.') 1690 self.add_param("partonlevel:mpi", True, hidden=True, always_write_to_card=False, 1691 comment='This allows to turn on/off MPI alltogether.') 1692 self.add_param("Beams:setProductionScalesFromLHEF", False, hidden=True, 1693 always_write_to_card=False, 1694 comment='This parameter is automatically set to True by MG5aMC when doing MLM merging with PY8.') 1695 1696 # for MLM merging 1697 self.add_param("JetMatching:merge", False, hidden=True, always_write_to_card=False, 1698 comment='Specifiy if we are merging sample of different multiplicity.') 1699 self.add_param("SysCalc:qCutList", [10.0,20.0], hidden=True, always_write_to_card=False) 1700 self['SysCalc:qCutList'] = 'auto' 1701 self.add_param("SysCalc:qWeed",-1.0,hidden=True, always_write_to_card=False, 1702 comment='Value of the merging scale below which one does not even write the HepMC event.') 1703 self.add_param("JetMatching:doVeto", False, hidden=True, always_write_to_card=False, 1704 comment='Do veto externally (e.g. in SysCalc).') 1705 self.add_param("JetMatching:scheme", 1, hidden=True, always_write_to_card=False) 1706 self.add_param("JetMatching:setMad", False, hidden=True, always_write_to_card=False, 1707 comment='Specify one must read inputs from the MadGraph banner.') 1708 self.add_param("JetMatching:coneRadius", 1.0, hidden=True, always_write_to_card=False) 1709 self.add_param("JetMatching:nQmatch",4,hidden=True, always_write_to_card=False) 1710 # for CKKWL merging (common with UMEPS, UNLOPS) 1711 self.add_param("TimeShower:pTmaxMatch", 2, hidden=True, always_write_to_card=False) 1712 self.add_param("SpaceShower:pTmaxMatch", 1, hidden=True, always_write_to_card=False) 1713 self.add_param("SysCalc:tmsList", [10.0,20.0], hidden=True, always_write_to_card=False) 1714 self['SysCalc:tmsList'] = 'auto' 1715 self.add_param("Merging:muFac", 91.188, hidden=True, always_write_to_card=False, 1716 comment='Set factorisation scales of the 2->2 process.') 1717 self.add_param("Merging:applyVeto", False, hidden=True, always_write_to_card=False, 1718 comment='Do veto externally (e.g. in SysCalc).') 1719 self.add_param("Merging:includeWeightInXsection", True, hidden=True, always_write_to_card=False, 1720 comment='If turned off, then the option belows forces PY8 to keep the original weight.') 1721 self.add_param("Merging:muRen", 91.188, hidden=True, always_write_to_card=False, 1722 comment='Set renormalization scales of the 2->2 process.') 1723 self.add_param("Merging:muFacInME", 91.188, hidden=True, always_write_to_card=False, 1724 comment='Set factorisation scales of the 2->2 Matrix Element.') 1725 self.add_param("Merging:muRenInME", 91.188, hidden=True, always_write_to_card=False, 1726 comment='Set renormalization scales of the 2->2 Matrix Element.') 1727 self.add_param("SpaceShower:rapidityOrder", False, hidden=True, always_write_to_card=False) 1728 self.add_param("Merging:nQuarksMerge",4,hidden=True, always_write_to_card=False) 1729 # To be added in subruns for CKKWL 1730 self.add_param("Merging:mayRemoveDecayProducts", False, hidden=True, always_write_to_card=False) 1731 self.add_param("Merging:doKTMerging", False, hidden=True, always_write_to_card=False) 1732 self.add_param("Merging:Dparameter", 0.4, hidden=True, always_write_to_card=False) 1733 self.add_param("Merging:doPTLundMerging", False, hidden=True, always_write_to_card=False) 1734 1735 # Special Pythia8 paremeters useful to simplify the shower. 1736 self.add_param("BeamRemnants:primordialKT", True, hidden=True, always_write_to_card=False, comment="see http://home.thep.lu.se/~torbjorn/pythia82html/BeamRemnants.html") 1737 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") 1738 self.add_param("Check:event", True, hidden=True, always_write_to_card=False, comment="check physical sanity of the events") 1739 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") 1740 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") 1741 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") 1742 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") 1743 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") 1744 self.add_param("ProcessLevel:resonanceDecays", True, hidden=True, always_write_to_card=False, comment="Do not allow unstable particle to decay.") 1745 1746 # Add parameters controlling the subruns execution flow. 1747 # These parameters should not be part of PY8SubRun daughter. 1748 self.add_default_subruns('parameters')
1749
1750 - def __init__(self, *args, **opts):
1751 # Parameters which are not printed in the card unless they are 1752 # 'user_set' or 'system_set' or part of the 1753 # self.hidden_params_to_always_print set. 1754 self.hidden_param = [] 1755 self.hidden_params_to_always_write = set() 1756 self.visible_params_to_always_write = set() 1757 # List of parameters that should never be written out given the current context. 1758 self.params_to_never_write = set() 1759 1760 # Parameters which have been set by the system (i.e. MG5 itself during 1761 # the regular course of the shower interface) 1762 self.system_set = set() 1763 1764 # Add attributes controlling the subruns execution flow. 1765 # These attributes should not be part of PY8SubRun daughter. 1766 self.add_default_subruns('attributes') 1767 1768 # Parameters which have been set by the 1769 super(PY8Card, self).__init__(*args, **opts)
1770 1771 1772
1773 - def add_param(self, name, value, hidden=False, always_write_to_card=True, 1774 comment=None):
1775 """ add a parameter to the card. value is the default value and 1776 defines the type (int/float/bool/str) of the input. 1777 The option 'hidden' decides whether the parameter should be visible to the user. 1778 The option 'always_write_to_card' decides whether it should 1779 always be printed or only when it is system_set or user_set. 1780 The option 'comment' can be used to specify a comment to write above 1781 hidden parameters. 1782 """ 1783 super(PY8Card, self).add_param(name, value, comment=comment) 1784 name = name.lower() 1785 if hidden: 1786 self.hidden_param.append(name) 1787 if always_write_to_card: 1788 self.hidden_params_to_always_write.add(name) 1789 else: 1790 if always_write_to_card: 1791 self.visible_params_to_always_write.add(name) 1792 if not comment is None: 1793 if not isinstance(comment, str): 1794 raise MadGraph5Error("Option 'comment' must be a string, not"+\ 1795 " '%s'."%str(comment))
1796
1797 - def add_subrun(self, py8_subrun):
1798 """Add a subrun to this PY8 Card.""" 1799 assert(isinstance(py8_subrun,PY8SubRun)) 1800 if py8_subrun['Main:subrun']==-1: 1801 raise MadGraph5Error("Make sure to correctly set the subrun ID"+\ 1802 " 'Main:subrun' *before* adding it to the PY8 Card.") 1803 if py8_subrun['Main:subrun'] in self.subruns: 1804 raise MadGraph5Error("A subrun with ID '%s'"%py8_subrun['Main:subrun']+\ 1805 " is already present in this PY8 card. Remove it first, or "+\ 1806 " access it directly.") 1807 self.subruns[py8_subrun['Main:subrun']] = py8_subrun 1808 if not 'LHEFInputs:nSubruns' in self.user_set: 1809 self['LHEFInputs:nSubruns'] = max(self.subruns.keys())
1810
1811 - def userSet(self, name, value, **opts):
1812 """Set an attribute of this card, following a user_request""" 1813 self.__setitem__(name, value, change_userdefine=True, **opts) 1814 if name.lower() in self.system_set: 1815 self.system_set.remove(name.lower())
1816
1817 - def vetoParamWriteOut(self, name):
1818 """ Forbid the writeout of a specific parameter of this card when the 1819 "write" function will be invoked.""" 1820 self.params_to_never_write.add(name.lower())
1821
1822 - def systemSet(self, name, value, **opts):
1823 """Set an attribute of this card, independently of a specific user 1824 request and only if not already user_set.""" 1825 try: 1826 force = opts.pop('force') 1827 except KeyError: 1828 force = False 1829 if force or name.lower() not in self.user_set: 1830 self.__setitem__(name, value, change_userdefine=False, **opts) 1831 self.system_set.add(name.lower())
1832
1833 - def MadGraphSet(self, name, value, **opts):
1834 """ Sets a card attribute, but only if it is absent or not already 1835 user_set.""" 1836 try: 1837 force = opts.pop('force') 1838 except KeyError: 1839 force = False 1840 if name.lower() not in self or (force or name.lower() not in self.user_set): 1841 self.__setitem__(name, value, change_userdefine=False, **opts) 1842 self.system_set.add(name.lower())
1843
1844 - def defaultSet(self, name, value, **opts):
1845 self.__setitem__(name, value, change_userdefine=False, **opts)
1846 1847 @staticmethod
1848 - def pythia8_formatting(value, formatv=None):
1849 """format the variable into pythia8 card convention. 1850 The type is detected by default""" 1851 if not formatv: 1852 if isinstance(value,UnknownType): 1853 formatv = 'unknown' 1854 elif isinstance(value, bool): 1855 formatv = 'bool' 1856 elif isinstance(value, int): 1857 formatv = 'int' 1858 elif isinstance(value, float): 1859 formatv = 'float' 1860 elif isinstance(value, str): 1861 formatv = 'str' 1862 elif isinstance(value, list): 1863 formatv = 'list' 1864 else: 1865 logger.debug("unknow format for pythia8_formatting: %s" , value) 1866 formatv = 'str' 1867 else: 1868 assert formatv 1869 1870 if formatv == 'unknown': 1871 # No formatting then 1872 return str(value) 1873 if formatv == 'bool': 1874 if str(value) in ['1','T','.true.','True','on']: 1875 return 'on' 1876 else: 1877 return 'off' 1878 elif formatv == 'int': 1879 try: 1880 return str(int(value)) 1881 except ValueError: 1882 fl = float(value) 1883 if int(fl) == fl: 1884 return str(int(fl)) 1885 else: 1886 raise 1887 elif formatv == 'float': 1888 return '%.10e' % float(value) 1889 elif formatv == 'shortfloat': 1890 return '%.3f' % float(value) 1891 elif formatv == 'str': 1892 return "%s" % value 1893 elif formatv == 'list': 1894 if len(value) and isinstance(value[0],float): 1895 return ','.join([PY8Card.pythia8_formatting(arg, 'shortfloat') for arg in value]) 1896 else: 1897 return ','.join([PY8Card.pythia8_formatting(arg) for arg in value])
1898 1899
1900 - def write(self, output_file, template, read_subrun=False, 1901 print_only_visible=False, direct_pythia_input=False, add_missing=True):
1902 """ Write the card to output_file using a specific template. 1903 > 'print_only_visible' specifies whether or not the hidden parameters 1904 should be written out if they are in the hidden_params_to_always_write 1905 list and system_set. 1906 > If 'direct_pythia_input' is true, then visible parameters which are not 1907 in the self.visible_params_to_always_write list and are not user_set 1908 or system_set are commented. 1909 > If 'add_missing' is False then parameters that should be written_out but are absent 1910 from the template will not be written out.""" 1911 1912 # First list the visible parameters 1913 visible_param = [p for p in self if p.lower() not in self.hidden_param 1914 or p.lower() in self.user_set] 1915 # Filter against list of parameters vetoed for write-out 1916 visible_param = [p for p in visible_param if p.lower() not in self.params_to_never_write] 1917 1918 # Now the hidden param which must be written out 1919 if print_only_visible: 1920 hidden_output_param = [] 1921 else: 1922 hidden_output_param = [p for p in self if p.lower() in self.hidden_param and 1923 not p.lower() in self.user_set and 1924 (p.lower() in self.hidden_params_to_always_write or 1925 p.lower() in self.system_set)] 1926 # Filter against list of parameters vetoed for write-out 1927 hidden_output_param = [p for p in hidden_output_param if p not in self.params_to_never_write] 1928 1929 if print_only_visible: 1930 subruns = [] 1931 else: 1932 if not read_subrun: 1933 subruns = sorted(self.subruns.keys()) 1934 1935 # Store the subruns to write in a dictionary, with its ID in key 1936 # and the corresponding stringstream in value 1937 subruns_to_write = {} 1938 1939 # Sort these parameters nicely so as to put together parameters 1940 # belonging to the same group (i.e. prefix before the ':' in their name). 1941 def group_params(params): 1942 if len(params)==0: 1943 return [] 1944 groups = {} 1945 for p in params: 1946 try: 1947 groups[':'.join(p.split(':')[:-1])].append(p) 1948 except KeyError: 1949 groups[':'.join(p.split(':')[:-1])] = [p,] 1950 res = sum(list(groups.values()),[]) 1951 # Make sure 'Main:subrun' appears first 1952 if 'Main:subrun' in res: 1953 res.insert(0,res.pop(res.index('Main:subrun'))) 1954 # Make sure 'LHEFInputs:nSubruns' appears last 1955 if 'LHEFInputs:nSubruns' in res: 1956 res.append(res.pop(res.index('LHEFInputs:nSubruns'))) 1957 return res
1958 1959 visible_param = group_params(visible_param) 1960 hidden_output_param = group_params(hidden_output_param) 1961 1962 # First dump in a temporary_output (might need to have a second pass 1963 # at the very end to update 'LHEFInputs:nSubruns') 1964 output = StringIO.StringIO() 1965 1966 # Setup template from which to read 1967 if isinstance(template, str): 1968 if os.path.isfile(template): 1969 tmpl = open(template, 'r') 1970 elif '\n' in template: 1971 tmpl = StringIO.StringIO(template) 1972 else: 1973 raise Exception("File input '%s' not found." % file_input) 1974 elif template is None: 1975 # Then use a dummy empty StringIO, hence skipping the reading 1976 tmpl = StringIO.StringIO() 1977 elif isinstance(template, (StringIO.StringIO, file)): 1978 tmpl = template 1979 else: 1980 raise MadGraph5Error("Incorrect type for argument 'template': %s"% 1981 template.__class__.__name__) 1982 1983 # Read the template 1984 last_pos = tmpl.tell() 1985 line = tmpl.readline() 1986 started_subrun_reading = False 1987 while line!='': 1988 # Skip comments 1989 if line.strip().startswith('!') or \ 1990 line.strip().startswith('\n') or\ 1991 line.strip() == '': 1992 output.write(line) 1993 # Proceed to next line 1994 last_pos = tmpl.tell() 1995 line = tmpl.readline() 1996 continue 1997 # Read parameter 1998 try: 1999 param_entry, value_entry = line.split('=') 2000 param = param_entry.strip() 2001 value = value_entry.strip() 2002 except ValueError: 2003 line = line.replace('\n','') 2004 raise MadGraph5Error("Could not read line '%s' of Pythia8 card."%\ 2005 line) 2006 # Read a subrun if detected: 2007 if param=='Main:subrun': 2008 if read_subrun: 2009 if not started_subrun_reading: 2010 # Record that the subrun reading has started and proceed 2011 started_subrun_reading = True 2012 else: 2013 # We encountered the next subrun. rewind last line and exit 2014 tmpl.seek(last_pos) 2015 break 2016 else: 2017 # Start the reading of this subrun 2018 tmpl.seek(last_pos) 2019 subruns_to_write[int(value)] = StringIO.StringIO() 2020 if int(value) in subruns: 2021 self.subruns[int(value)].write(subruns_to_write[int(value)], 2022 tmpl,read_subrun=True) 2023 # Remove this subrun ID from the list 2024 subruns.pop(subruns.index(int(value))) 2025 else: 2026 # Unknow subrun, create a dummy one 2027 DummySubrun=PY8SubRun() 2028 # Remove all of its variables (so that nothing is overwritten) 2029 DummySubrun.clear() 2030 DummySubrun.write(subruns_to_write[int(value)], 2031 tmpl, read_subrun=True, 2032 print_only_visible=print_only_visible, 2033 direct_pythia_input=direct_pythia_input) 2034 2035 logger.info('Adding new unknown subrun with ID %d.'% 2036 int(value)) 2037 # Proceed to next line 2038 last_pos = tmpl.tell() 2039 line = tmpl.readline() 2040 continue 2041 2042 # Change parameters which must be output 2043 if param in visible_param: 2044 new_value = PY8Card.pythia8_formatting(self[param]) 2045 visible_param.pop(visible_param.index(param)) 2046 elif param in hidden_output_param: 2047 new_value = PY8Card.pythia8_formatting(self[param]) 2048 hidden_output_param.pop(hidden_output_param.index(param)) 2049 else: 2050 # Just copy parameters which don't need to be specified 2051 if param.lower() not in self.params_to_never_write: 2052 output.write(line) 2053 else: 2054 output.write('! The following parameter was forced to be commented out by MG5aMC.\n') 2055 output.write('! %s'%line) 2056 # Proceed to next line 2057 last_pos = tmpl.tell() 2058 line = tmpl.readline() 2059 continue 2060 2061 # Substitute the value. 2062 # If it is directly the pytia input, then don't write the param if it 2063 # is not in the list of visible_params_to_always_write and was 2064 # not user_set or system_set 2065 if ((not direct_pythia_input) or 2066 (param.lower() in self.visible_params_to_always_write) or 2067 (param.lower() in self.user_set) or 2068 (param.lower() in self.system_set)): 2069 template = '%s=%s' 2070 else: 2071 # These are parameters that the user can edit in AskEditCards 2072 # but if neither the user nor the system edited them, 2073 # then they shouldn't be passed to Pythia 2074 template = '!%s=%s' 2075 2076 output.write(template%(param_entry, 2077 value_entry.replace(value,new_value))) 2078 2079 # Proceed to next line 2080 last_pos = tmpl.tell() 2081 line = tmpl.readline() 2082 2083 # If add_missing is False, make sure to empty the list of remaining parameters 2084 if not add_missing: 2085 visible_param = [] 2086 hidden_output_param = [] 2087 2088 # Now output the missing parameters. Warn about visible ones. 2089 if len(visible_param)>0 and not template is None: 2090 output.write( 2091 """! 2092 ! Additional general parameters%s. 2093 ! 2094 """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else '')) 2095 for param in visible_param: 2096 value = PY8Card.pythia8_formatting(self[param]) 2097 output.write('%s=%s\n'%(param,value)) 2098 if template is None: 2099 if param=='Main:subrun': 2100 output.write( 2101 """! 2102 ! Definition of subrun %d 2103 ! 2104 """%self['Main:subrun']) 2105 elif param.lower() not in self.hidden_param: 2106 logger.debug('Adding parameter %s (missing in the template) to current '+\ 2107 'pythia8 card (with value %s)',param, value) 2108 2109 if len(hidden_output_param)>0 and not template is None: 2110 output.write( 2111 """! 2112 ! Additional technical parameters%s set by MG5_aMC. 2113 ! 2114 """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else '')) 2115 for param in hidden_output_param: 2116 if param.lower() in self.comments: 2117 comment = '\n'.join('! %s'%c for c in 2118 self.comments[param.lower()].split('\n')) 2119 output.write(comment+'\n') 2120 output.write('%s=%s\n'%(param,PY8Card.pythia8_formatting(self[param]))) 2121 2122 # Don't close the file if we were reading a subrun, but simply write 2123 # output and return now 2124 if read_subrun: 2125 output_file.write(output.getvalue()) 2126 return 2127 2128 # Now add subruns not present in the template 2129 for subrunID in subruns: 2130 new_subrun = StringIO.StringIO() 2131 self.subruns[subrunID].write(new_subrun,None,read_subrun=True) 2132 subruns_to_write[subrunID] = new_subrun 2133 2134 # Add all subruns to the output, in the right order 2135 for subrunID in sorted(subruns_to_write): 2136 output.write(subruns_to_write[subrunID].getvalue()) 2137 2138 # If 'LHEFInputs:nSubruns' is not user_set, then make sure it is 2139 # updated at least larger or equal to the maximum SubRunID 2140 if 'LHEFInputs:nSubruns'.lower() not in self.user_set and \ 2141 len(subruns_to_write)>0 and 'LHEFInputs:nSubruns' in self\ 2142 and self['LHEFInputs:nSubruns']<max(subruns_to_write.keys()): 2143 logger.info("Updating PY8 parameter 'LHEFInputs:nSubruns' to "+ 2144 "%d so as to cover all defined subruns."%max(subruns_to_write.keys())) 2145 self['LHEFInputs:nSubruns'] = max(subruns_to_write.keys()) 2146 output = StringIO.StringIO() 2147 self.write(output,template,print_only_visible=print_only_visible) 2148 2149 # Write output 2150 if isinstance(output_file, str): 2151 out = open(output_file,'w') 2152 out.write(output.getvalue()) 2153 out.close() 2154 else: 2155 output_file.write(output.getvalue())
2156
2157 - def read(self, file_input, read_subrun=False, setter='default'):
2158 """Read the input file, this can be a path to a file, 2159 a file object, a str with the content of the file. 2160 The setter option choses the authority that sets potential 2161 modified/new parameters. It can be either: 2162 'default' or 'user' or 'system'""" 2163 if isinstance(file_input, str): 2164 if "\n" in file_input: 2165 finput = StringIO.StringIO(file_input) 2166 elif os.path.isfile(file_input): 2167 finput = open(file_input) 2168 else: 2169 raise Exception("File input '%s' not found." % file_input) 2170 elif isinstance(file_input, (StringIO.StringIO, file)): 2171 finput = file_input 2172 else: 2173 raise MadGraph5Error("Incorrect type for argument 'file_input': %s"% 2174 file_input.__class__.__name__) 2175 2176 # Read the template 2177 last_pos = finput.tell() 2178 line = finput.readline() 2179 started_subrun_reading = False 2180 while line!='': 2181 # Skip comments 2182 if line.strip().startswith('!') or line.strip()=='': 2183 # proceed to next line 2184 last_pos = finput.tell() 2185 line = finput.readline() 2186 continue 2187 # Read parameter 2188 try: 2189 param, value = line.split('=',1) 2190 param = param.strip() 2191 value = value.strip() 2192 except ValueError: 2193 line = line.replace('\n','') 2194 raise MadGraph5Error("Could not read line '%s' of Pythia8 card."%\ 2195 line) 2196 if '!' in value: 2197 value,_ = value.split('!',1) 2198 2199 # Read a subrun if detected: 2200 if param=='Main:subrun': 2201 if read_subrun: 2202 if not started_subrun_reading: 2203 # Record that the subrun reading has started and proceed 2204 started_subrun_reading = True 2205 else: 2206 # We encountered the next subrun. rewind last line and exit 2207 finput.seek(last_pos) 2208 return 2209 else: 2210 # Start the reading of this subrun 2211 finput.seek(last_pos) 2212 if int(value) in self.subruns: 2213 self.subruns[int(value)].read(finput,read_subrun=True, 2214 setter=setter) 2215 else: 2216 # Unknow subrun, create a dummy one 2217 NewSubrun=PY8SubRun() 2218 NewSubrun.read(finput,read_subrun=True, setter=setter) 2219 self.add_subrun(NewSubrun) 2220 2221 # proceed to next line 2222 last_pos = finput.tell() 2223 line = finput.readline() 2224 continue 2225 2226 # Read parameter. The case of a parameter not defined in the card is 2227 # handled directly in ConfigFile. 2228 2229 # Use the appropriate authority to set the new/changed variable 2230 if setter == 'user': 2231 self.userSet(param,value) 2232 elif setter == 'system': 2233 self.systemSet(param,value) 2234 else: 2235 self.defaultSet(param,value) 2236 2237 # proceed to next line 2238 last_pos = finput.tell() 2239 line = finput.readline()
2240
2241 -class PY8SubRun(PY8Card):
2242 """ Class to characterize a specific PY8 card subrun section. """ 2243
2244 - def add_default_subruns(self, type):
2245 """ Overloading of the homonym function called in the __init__ of PY8Card. 2246 The initialization of the self.subruns attribute should of course not 2247 be performed in PY8SubRun.""" 2248 pass
2249
2250 - def __init__(self, *args, **opts):
2251 """ Initialize a subrun """ 2252 2253 # Force user to set it manually. 2254 subrunID = -1 2255 if 'subrun_id' in opts: 2256 subrunID = opts.pop('subrun_id') 2257 2258 super(PY8SubRun, self).__init__(*args, **opts) 2259 self['Main:subrun']=subrunID
2260
2261 - def default_setup(self):
2262 """Sets up the list of available PY8SubRun parameters.""" 2263 2264 # Add all default PY8Card parameters 2265 super(PY8SubRun, self).default_setup() 2266 # Make sure they are all hidden 2267 self.hidden_param = [k.lower() for k in self.keys()] 2268 self.hidden_params_to_always_write = set() 2269 self.visible_params_to_always_write = set() 2270 2271 # Now add Main:subrun and Beams:LHEF. They are not hidden. 2272 self.add_param("Main:subrun", -1) 2273 self.add_param("Beams:LHEF", "events.lhe.gz")
2274 2275 2276 2277 runblock = collections.namedtuple('block', ('name', 'fields', 'template_on', 'template_off'))
2278 -class RunCard(ConfigFile):
2279 2280 filename = 'run_card' 2281 LO = True 2282 blocks = [] 2283
2284 - def __new__(cls, finput=None, **opt):
2285 if cls is RunCard: 2286 if not finput: 2287 target_class = RunCardLO 2288 elif isinstance(finput, cls): 2289 target_class = finput.__class__ 2290 elif isinstance(finput, str): 2291 if '\n' not in finput: 2292 finput = open(finput).read() 2293 if 'req_acc_FO' in finput: 2294 target_class = RunCardNLO 2295 else: 2296 target_class = RunCardLO 2297 else: 2298 return None 2299 return super(RunCard, cls).__new__(target_class, finput, **opt) 2300 else: 2301 return super(RunCard, cls).__new__(cls, finput, **opt)
2302
2303 - def __init__(self, *args, **opts):
2304 2305 # The following parameter are updated in the defaultsetup stage. 2306 2307 #parameter for which no warning should be raised if not define 2308 self.hidden_param = [] 2309 # in which include file the parameer should be written 2310 self.includepath = collections.defaultdict(list) 2311 #some parameter have different name in fortran code 2312 self.fortran_name = {} 2313 #parameter which are not supported anymore. (no action on the code) 2314 self.legacy_parameter = {} 2315 #a list with all the cuts variable and which type object impacted 2316 # L means charged lepton (l) and neutral lepton (n) 2317 # d means that it is related to decay chain 2318 # J means both light jet (j) and heavy jet (b) 2319 # aj/jl/bj/bl/al are also possible (and stuff like aa/jj/llll/... 2320 self.cuts_parameter = {} 2321 # parameter added where legacy requires an older value. 2322 self.system_default = {} 2323 2324 self.display_block = [] # set some block to be displayed 2325 self.cut_class = {} 2326 self.warned=False 2327 2328 2329 super(RunCard, self).__init__(*args, **opts)
2330
2331 - def add_param(self, name, value, fortran_name=None, include=True, 2332 hidden=False, legacy=False, cut=False, system=False, sys_default=None, 2333 **opts):
2334 """ add a parameter to the card. value is the default value and 2335 defines the type (int/float/bool/str) of the input. 2336 fortran_name defines what is the associate name in the f77 code 2337 include defines if we have to put the value in the include file 2338 hidden defines if the parameter is expected to be define by the user. 2339 legacy:Parameter which is not used anymore (raise a warning if not default) 2340 cut: defines the list of cut parameter to allow to set them all to off. 2341 sys_default: default used if the parameter is not in the card 2342 2343 options of **opts: 2344 - allowed: list of valid options. '*' means anything else should be allowed. 2345 empty list means anything possible as well. 2346 - comment: add comment for writing/help 2347 - typelist: type of the list if default is empty 2348 """ 2349 2350 super(RunCard, self).add_param(name, value, system=system,**opts) 2351 name = name.lower() 2352 if fortran_name: 2353 self.fortran_name[name] = fortran_name 2354 if legacy: 2355 self.legacy_parameter[name] = value 2356 include = False 2357 self.includepath[include].append(name) 2358 if hidden or system: 2359 self.hidden_param.append(name) 2360 if cut: 2361 self.cuts_parameter[name] = cut 2362 if sys_default is not None: 2363 self.system_default[name] = sys_default
2364 2365 2366
2367 - def read(self, finput, consistency=True):
2368 """Read the input file, this can be a path to a file, 2369 a file object, a str with the content of the file.""" 2370 2371 if isinstance(finput, str): 2372 if "\n" in finput: 2373 finput = finput.split('\n') 2374 elif os.path.isfile(finput): 2375 finput = open(finput) 2376 else: 2377 raise Exception("No such file %s" % finput) 2378 2379 for line in finput: 2380 line = line.split('#')[0] 2381 line = line.split('!')[0] 2382 line = line.rsplit('=',1) 2383 if len(line) != 2: 2384 continue 2385 value, name = line 2386 name = name.lower().strip() 2387 if name not in self and ('min' in name or 'max' in name): 2388 #looks like an entry added by one user -> add it nicely 2389 self.add_param(name, float(value), hidden=True, cut=True) 2390 else: 2391 self.set( name, value, user=True) 2392 # parameter not set in the run_card can be set to compatiblity value 2393 if consistency: 2394 try: 2395 self.check_validity() 2396 except InvalidRunCard as error: 2397 if consistency == 'warning': 2398 logger.warning(str(error)) 2399 else: 2400 raise
2401
2402 - def valid_line(self, line, tmp):
2403 template_options = tmp 2404 default = template_options['default'] 2405 if line.startswith('#IF('): 2406 cond = line[4:line.find(')')] 2407 if template_options.get(cond, default): 2408 return True 2409 else: 2410 return False 2411 elif line.strip().startswith('%'): 2412 parameter = line[line.find('(')+1:line.find(')')] 2413 2414 try: 2415 cond = self.cuts_parameter[parameter] 2416 except KeyError: 2417 return True 2418 2419 2420 if template_options.get(cond, default) or cond is True: 2421 return True 2422 else: 2423 return False 2424 else: 2425 return True
2426 2427
2428 - def write(self, output_file, template=None, python_template=False, 2429 write_hidden=False, template_options=None):
2430 """Write the run_card in output_file according to template 2431 (a path to a valid run_card)""" 2432 2433 to_write = set(self.user_set) 2434 written = set() 2435 if not template: 2436 raise Exception 2437 if not template_options: 2438 template_options = collections.defaultdict(str) 2439 2440 # check which optional block to write: 2441 write_block= [] 2442 for b in self.blocks: 2443 name = b.name 2444 # check if the block has to be written 2445 if name not in self.display_block and \ 2446 not any(f in self.user_set for f in b.fields): 2447 continue 2448 write_block.append(b.name) 2449 2450 2451 if python_template: 2452 text = open(template,'r').read() 2453 text = text.split('\n') 2454 # remove if templating 2455 text = [l if not l.startswith('#IF') else l[l.find(')# ')+2:] 2456 for l in text if self.valid_line(l, template_options)] 2457 text ='\n'.join(text) 2458 2459 if python_template and not to_write: 2460 import string 2461 if self.blocks: 2462 text = string.Template(text) 2463 mapping = {} 2464 for b in self.blocks: 2465 if b.name in write_block: 2466 mapping[b.name] = b.template_on 2467 else: 2468 mapping[b.name] = b.template_off 2469 text = text.substitute(mapping) 2470 2471 if not self.list_parameter: 2472 text = text % self 2473 else: 2474 data = dict((key.lower(),value) for key, value in self.items()) 2475 for name in self.list_parameter: 2476 if self.list_parameter[name] != str: 2477 data[name] = ', '.join(str(v) for v in data[name]) 2478 else: 2479 data[name] = "['%s']" % "', '".join(str(v) for v in data[name]) 2480 text = text % data 2481 else: 2482 text = "" 2483 for line in open(template,'r'): 2484 nline = line.split('#')[0] 2485 nline = nline.split('!')[0] 2486 comment = line[len(nline):] 2487 nline = nline.rsplit('=',1) 2488 if python_template and nline[0].startswith('$'): 2489 block_name = nline[0][1:].strip() 2490 this_group = [b for b in self.blocks if b.name == block_name] 2491 if not this_group: 2492 logger.debug("block %s not defined", block_name) 2493 continue 2494 else: 2495 this_group = this_group[0] 2496 if block_name in write_block: 2497 text += this_group.template_on % self 2498 for name in this_group.fields: 2499 written.add(name) 2500 if name in to_write: 2501 to_write.remove(name) 2502 else: 2503 text += this_group.template_off % self 2504 2505 elif len(nline) != 2: 2506 text += line 2507 elif nline[1].strip() in self: 2508 2509 name = nline[1].strip().lower() 2510 value = self[name] 2511 if name in self.list_parameter: 2512 if self.list_parameter[name] != str: 2513 value = ', '.join([str(v) for v in value]) 2514 else: 2515 value = "['%s']" % "', '".join(str(v) for v in value) 2516 if python_template: 2517 text += line % {nline[1].strip():value, name:value} 2518 written.add(name) 2519 else: 2520 if not comment or comment[-1]!='\n': 2521 endline = '\n' 2522 else: 2523 endline = '' 2524 text += ' %s\t= %s %s%s' % (value, name, comment, endline) 2525 written.add(name) 2526 2527 if name in to_write: 2528 to_write.remove(name) 2529 else: 2530 logger.info('Adding missing parameter %s to current %s (with default value)', 2531 (name, self.filename)) 2532 written.add(name) 2533 text += line 2534 2535 for b in self.blocks: 2536 if b.name not in write_block: 2537 continue 2538 # check if all attribute of the block have been written already 2539 if all(f in written for f in b.fields): 2540 continue 2541 2542 to_add = [''] 2543 for line in b.template_on.split('\n'): 2544 nline = line.split('#')[0] 2545 nline = nline.split('!')[0] 2546 nline = nline.split('=') 2547 if len(nline) != 2: 2548 to_add.append(line) 2549 elif nline[1].strip() in self: 2550 name = nline[1].strip().lower() 2551 value = self[name] 2552 if name in self.list_parameter: 2553 value = ', '.join([str(v) for v in value]) 2554 if name in written: 2555 continue #already include before 2556 else: 2557 to_add.append(line % {nline[1].strip():value, name:value}) 2558 written.add(name) 2559 2560 if name in to_write: 2561 to_write.remove(name) 2562 else: 2563 raise Exception 2564 2565 if b.template_off and b.template_off in text: 2566 text = text.replace(b.template_off, '\n'.join(to_add)) 2567 else: 2568 text += '\n'.join(to_add) 2569 2570 if to_write or write_hidden: 2571 text+="""#********************************************************************* 2572 # Additional hidden parameters 2573 #********************************************************************* 2574 """ 2575 if write_hidden: 2576 # 2577 # do not write hidden parameter not hidden for this template 2578 # 2579 if python_template: 2580 written = written.union(set(re.findall('\%\((\w*)\)s', open(template,'r').read(), re.M))) 2581 to_write = to_write.union(set(self.hidden_param)) 2582 to_write = to_write.difference(written) 2583 2584 for key in to_write: 2585 if key in self.system_only: 2586 continue 2587 2588 comment = self.comments.get(key,'hidden_parameter').replace('\n','\n#') 2589 text += ' %s\t= %s # %s\n' % (self[key], key, comment) 2590 2591 if isinstance(output_file, str): 2592 fsock = open(output_file,'w') 2593 fsock.write(text) 2594 fsock.close() 2595 else: 2596 output_file.write(text)
2597 2598
2599 - def get_default(self, name, default=None, log_level=None):
2600 """return self[name] if exist otherwise default. log control if we 2601 put a warning or not if we use the default value""" 2602 2603 lower_name = name.lower() 2604 if lower_name not in self.user_set: 2605 if log_level is None: 2606 if lower_name in self.system_only: 2607 log_level = 5 2608 elif lower_name in self.auto_set: 2609 log_level = 5 2610 elif lower_name in self.hidden_param: 2611 log_level = 10 2612 elif lower_name in self.cuts_parameter: 2613 if not MADEVENT and madgraph.ADMIN_DEBUG: 2614 log_level = 5 2615 else: 2616 log_level = 10 2617 else: 2618 log_level = 20 2619 if not default: 2620 default = dict.__getitem__(self, name.lower()) 2621 2622 logger.log(log_level, '%s missed argument %s. Takes default: %s' 2623 % (self.filename, name, default)) 2624 self[name] = default 2625 return default 2626 else: 2627 return self[name]
2628 2629 2630 @staticmethod
2631 - def f77_formatting(value, formatv=None):
2632 """format the variable into fortran. The type is detected by default""" 2633 2634 if not formatv: 2635 if isinstance(value, bool): 2636 formatv = 'bool' 2637 elif isinstance(value, int): 2638 formatv = 'int' 2639 elif isinstance(value, float): 2640 formatv = 'float' 2641 elif isinstance(value, str): 2642 formatv = 'str' 2643 else: 2644 logger.debug("unknow format for f77_formatting: %s" , str(value)) 2645 formatv = 'str' 2646 else: 2647 assert formatv 2648 2649 if formatv == 'bool': 2650 if str(value) in ['1','T','.true.','True']: 2651 return '.true.' 2652 else: 2653 return '.false.' 2654 2655 elif formatv == 'int': 2656 try: 2657 return str(int(value)) 2658 except ValueError: 2659 fl = float(value) 2660 if int(fl) == fl: 2661 return str(int(fl)) 2662 else: 2663 raise 2664 2665 elif formatv == 'float': 2666 if isinstance(value, str): 2667 value = value.replace('d','e') 2668 return ('%.10e' % float(value)).replace('e','d') 2669 2670 elif formatv == 'str': 2671 # Check if it is a list 2672 if value.strip().startswith('[') and value.strip().endswith(']'): 2673 elements = (value.strip()[1:-1]).split() 2674 return ['_length = %d'%len(elements)]+\ 2675 ['(%d) = %s'%(i+1, elem.strip()) for i, elem in \ 2676 enumerate(elements)] 2677 else: 2678 return "'%s'" % value
2679 2680 2681
2682 - def check_validity(self, log_level=30):
2683 """check that parameter missing in the card are set to the expected value""" 2684 2685 for name, value in self.system_default.items(): 2686 self.set(name, value, changeifuserset=False) 2687 2688 2689 for name in self.includepath[False]: 2690 to_bypass = self.hidden_param + list(self.legacy_parameter.keys()) 2691 if name not in to_bypass: 2692 self.get_default(name, log_level=log_level) 2693 2694 for name in self.legacy_parameter: 2695 if self[name] != self.legacy_parameter[name]: 2696 logger.warning("The parameter %s is not supported anymore this parameter will be ignored." % name)
2697 2698 default_include_file = 'run_card.inc' 2699
2701 """update hidden system only parameter for the correct writtin in the 2702 include""" 2703 return
2704
2705 - def write_include_file(self, output_dir):
2706 """Write the various include file in output_dir. 2707 The entry True of self.includepath will be written in run_card.inc 2708 The entry False will not be written anywhere""" 2709 2710 # ensure that all parameter are coherent and fix those if needed 2711 self.check_validity() 2712 2713 #ensusre that system only parameter are correctly set 2714 self.update_system_parameter_for_include() 2715 2716 for incname in self.includepath: 2717 if incname is True: 2718 pathinc = self.default_include_file 2719 elif incname is False: 2720 continue 2721 else: 2722 pathinc = incname 2723 2724 fsock = file_writers.FortranWriter(pjoin(output_dir,pathinc)) 2725 for key in self.includepath[incname]: 2726 #define the fortran name 2727 if key in self.fortran_name: 2728 fortran_name = self.fortran_name[key] 2729 else: 2730 fortran_name = key 2731 2732 #get the value with warning if the user didn't set it 2733 value = self.get_default(key) 2734 # Special treatment for strings containing a list of 2735 # strings. Convert it to a list of strings 2736 if isinstance(value, list): 2737 # in case of a list, add the length of the list as 0th 2738 # element in fortran. Only in case of integer or float 2739 # list (not for bool nor string) 2740 targettype = self.list_parameter[key] 2741 if targettype is bool: 2742 pass 2743 elif targettype is int: 2744 line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(len(value))) 2745 fsock.writelines(line) 2746 elif targettype is float: 2747 line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(float(len(value)))) 2748 fsock.writelines(line) 2749 # output the rest of the list in fortran 2750 for i,v in enumerate(value): 2751 line = '%s(%s) = %s \n' % (fortran_name, i+1, self.f77_formatting(v)) 2752 fsock.writelines(line) 2753 elif isinstance(value, dict): 2754 for fortran_name, onevalue in value.items(): 2755 line = '%s = %s \n' % (fortran_name, self.f77_formatting(onevalue)) 2756 fsock.writelines(line) 2757 elif isinstance(incname,str) and 'compile' in incname: 2758 line = '%s = %s \n' % (fortran_name, value) 2759 fsock.write(line) 2760 else: 2761 line = '%s = %s \n' % (fortran_name, self.f77_formatting(value)) 2762 fsock.writelines(line) 2763 fsock.close()
2764 2765 @staticmethod
2766 - def get_idbmup(lpp):
2767 """return the particle colliding pdg code""" 2768 if lpp in (1,2, -1,-2): 2769 return math.copysign(2212, lpp) 2770 elif lpp in (3,-3): 2771 return math.copysign(11, lpp) 2772 elif lpp == 0: 2773 #logger.critical("Fail to write correct idbmup in the lhe file. Please correct those by hand") 2774 return 0 2775 else: 2776 return lpp
2777
2779 """return a dictionary with the information needed to write 2780 the first line of the <init> block of the lhe file.""" 2781 2782 output = {} 2783 output["idbmup1"] = self.get_idbmup(self['lpp1']) 2784 output["idbmup2"] = self.get_idbmup(self['lpp2']) 2785 output["ebmup1"] = self["ebeam1"] 2786 output["ebmup2"] = self["ebeam2"] 2787 output["pdfgup1"] = 0 2788 output["pdfgup2"] = 0 2789 output["pdfsup1"] = self.get_pdf_id(self["pdlabel"]) 2790 output["pdfsup2"] = self.get_pdf_id(self["pdlabel"]) 2791 return output
2792
2793 - def get_pdf_id(self, pdf):
2794 if pdf == "lhapdf": 2795 lhaid = self["lhaid"] 2796 if isinstance(lhaid, list): 2797 return lhaid[0] 2798 else: 2799 return lhaid 2800 else: 2801 return {'none': 0, 2802 'cteq6_m':10000,'cteq6_l':10041,'cteq6l1':10042, 2803 'nn23lo':246800,'nn23lo1':247000,'nn23nlo':244800 2804 }[pdf]
2805
2806 - def get_lhapdf_id(self):
2807 return self.get_pdf_id(self['pdlabel'])
2808
2809 - def remove_all_cut(self):
2810 """remove all the cut""" 2811 2812 for name in self.cuts_parameter: 2813 targettype = type(self[name]) 2814 if targettype == bool: 2815 self[name] = False 2816 if targettype == dict: 2817 self[name] = '{}' 2818 elif 'min' in name: 2819 self[name] = 0 2820 elif 'max' in name: 2821 self[name] = -1 2822 elif 'eta' in name: 2823 self[name] = -1 2824 else: 2825 self[name] = 0
2826
2827 -class RunCardLO(RunCard):
2828 """an object to handle in a nice way the run_card information""" 2829 2830 blocks = [ 2831 # HEAVY ION OPTIONAL BLOCK 2832 runblock(name='ion_pdf', fields=('nb_neutron1', 'nb_neutron2','nb_proton1','nb_proton2','mass_ion1', 'mass_ion2'), 2833 template_on=\ 2834 """#********************************************************************* 2835 # Heavy ion PDF / rescaling of PDF * 2836 #********************************************************************* 2837 %(nb_proton1)s = nb_proton1 # number of proton for the first beam 2838 %(nb_neutron1)s = nb_neutron1 # number of neutron for the first beam 2839 %(mass_ion1)s = mass_ion1 # mass of the heavy ion (first beam) 2840 # Note that seting differently the two beams only work if you use 2841 # group_subprocess=False when generating your matrix-element 2842 %(nb_proton2)s = nb_proton2 # number of proton for the second beam 2843 %(nb_neutron2)s = nb_neutron2 # number of neutron for the second beam 2844 %(mass_ion2)s = mass_ion2 # mass of the heavy ion (second beam) 2845 """, 2846 template_off='# To see heavy ion options: type "update ion_pdf"'), 2847 2848 2849 # BEAM POLARIZATION OPTIONAL BLOCK 2850 runblock(name='beam_pol', fields=('polbeam1','polbeam2'), 2851 template_on=\ 2852 """#********************************************************************* 2853 # Beam polarization from -100 (left-handed) to 100 (right-handed) * 2854 #********************************************************************* 2855 %(polbeam1)s = polbeam1 ! beam polarization for beam 1 2856 %(polbeam2)s = polbeam2 ! beam polarization for beam 2 2857 """, 2858 template_off='# To see polarised beam options: type "update beam_pol"'), 2859 2860 # SYSCALC OPTIONAL BLOCK 2861 runblock(name='syscalc', fields=('sys_scalefact', 'sys_alpsfact','sys_matchscale','sys_pdf'), 2862 template_on=\ 2863 """#************************************** 2864 # Parameter below of the systematics study 2865 # will be used by SysCalc (if installed) 2866 #************************************** 2867 # 2868 %(sys_scalefact)s = sys_scalefact # factorization/renormalization scale factor 2869 %(sys_alpsfact)s = sys_alpsfact # \alpha_s emission scale factors 2870 %(sys_matchscale)s = sys_matchscale # variation of merging scale 2871 # PDF sets and number of members (0 or none for all members). 2872 %(sys_pdf)s = sys_pdf # list of pdf sets. (errorset not valid for syscalc) 2873 # MSTW2008nlo68cl.LHgrid 1 = sys_pdf 2874 # 2875 """, 2876 template_off= '# Syscalc is deprecated but to see the associate options type\'update syscalc\''), 2877 2878 # ECUT block (hidden it by default but for e+ e- collider) 2879 runblock(name='ecut', fields=('ej','eb','ea','el','ejmax','ebmax','eamax','elmax','e_min_pdg','e_max_pdg'), 2880 template_on=\ 2881 """#********************************************************************* 2882 # Minimum and maximum E's (in the center of mass frame) * 2883 #********************************************************************* 2884 %(ej)s = ej ! minimum E for the jets 2885 %(eb)s = eb ! minimum E for the b 2886 %(ea)s = ea ! minimum E for the photons 2887 %(el)s = el ! minimum E for the charged leptons 2888 %(ejmax)s = ejmax ! maximum E for the jets 2889 %(ebmax)s = ebmax ! maximum E for the b 2890 %(eamax)s = eamax ! maximum E for the photons 2891 %(elmax)s = elmax ! maximum E for the charged leptons 2892 %(e_min_pdg)s = e_min_pdg ! E cut for other particles (use pdg code). Applied on particle and anti-particle 2893 %(e_max_pdg)s = e_max_pdg ! E cut for other particles (syntax e.g. {6: 100, 25: 50}) 2894 """, 2895 template_off= '#\n# For display option for energy cut in the partonic center of mass frame type \'update ecut\'\n#'), 2896 2897 # Frame for polarization 2898 runblock(name='frame', fields=('me_frame'), 2899 template_on=\ 2900 """#********************************************************************* 2901 # Frame where to evaluate the matrix-element (not the cut!) for polarization 2902 #********************************************************************* 2903 %(me_frame)s = me_frame ! list of particles to sum-up to define the rest-frame 2904 ! in which to evaluate the matrix-element 2905 ! [1,2] means the partonic center of mass 2906 """, 2907 template_off= ''), 2908 # MERGING BLOCK: MLM 2909 runblock(name='mlm', fields=('ickkw','alpsfact','chcluster','asrwgtflavor','auto_ptj_mjj','xqcut'), 2910 template_on=\ 2911 """#********************************************************************* 2912 # Matching parameter (MLM only) 2913 #********************************************************************* 2914 %(ickkw)s = ickkw ! 0 no matching, 1 MLM 2915 %(alpsfact)s = alpsfact ! scale factor for QCD emission vx 2916 %(chcluster)s = chcluster ! cluster only according to channel diag 2917 %(asrwgtflavor)s = asrwgtflavor ! highest quark flavor for a_s reweight 2918 %(auto_ptj_mjj)s = auto_ptj_mjj ! Automatic setting of ptj and mjj if xqcut >0 2919 ! (turn off for VBF and single top processes) 2920 %(xqcut)s = xqcut ! minimum kt jet measure between partons 2921 """, 2922 template_off='# To see MLM/CKKW merging options: type "update MLM" or "update CKKW"'), 2923 2924 # MERGING BLOCK: CKKW 2925 runblock(name='ckkw', fields=('ktdurhham','dparameter','ptlund','pdgs_for_merging_cut'), 2926 template_on=\ 2927 """#*********************************************************************** 2928 # Turn on either the ktdurham or ptlund cut to activate * 2929 # CKKW(L) merging with Pythia8 [arXiv:1410.3012, arXiv:1109.4829] * 2930 #*********************************************************************** 2931 %(ktdurham)s = ktdurham 2932 %(dparameter)s = dparameter 2933 %(ptlund)s = ptlund 2934 %(pdgs_for_merging_cut)s = pdgs_for_merging_cut ! PDGs for two cuts above 2935 """, 2936 template_off=''), 2937 # PS-OPTIM BLOCK: PSOPTIM 2938 runblock(name='psoptim', fields=('job_strategy', 'hard_survey', 2939 'tmin_for_channel', 'survey_splitting', 2940 'survey_nchannel_per_job', 'refine_evt_by_job' 2941 'global_flag','aloha_flag', 'matrix_flag' 2942 ), 2943 template_on=\ 2944 """#********************************************************************* 2945 # Phase-Space Optim (advanced) 2946 #********************************************************************* 2947 %(job_strategy)s = job_strategy ! see appendix of 1507.00020 (page 26) 2948 %(hard_survey)s = hard_survey ! force to have better estimate of the integral at survey for difficult mode like interference 2949 %(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 2950 %(survey_splitting)s = survey_splitting ! for loop-induced control how many core are used at survey for the computation of a single iteration. 2951 %(survey_nchannel_per_job)s = survey_nchannel_per_job ! control how many Channel are integrated inside a single job on cluster/multicore 2952 %(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) 2953 #********************************************************************* 2954 # Compilation flag. No automatic re-compilation (need manual "make clean" in Source) 2955 #********************************************************************* 2956 %(global_flag)s = global_flag ! fortran optimization flag use for the all code. 2957 %(aloha_flag)s = aloha_flag ! fortran optimization flag for aloha function. Suggestions: '-ffast-math' 2958 %(matrix_flag)s = matrix_flag ! fortran optimization flag for matrix.f function. Suggestions: '-O3' 2959 """, 2960 template_off='# To see advanced option for Phase-Space optimization: type "update psoptim"'), 2961 ] 2962 2963
2964 - def default_setup(self):
2965 """default value for the run_card.dat""" 2966 2967 self.add_param("run_tag", "tag_1", include=False) 2968 self.add_param("gridpack", False) 2969 self.add_param("time_of_flight", -1.0, include=False) 2970 self.add_param("nevents", 10000) 2971 self.add_param("iseed", 0) 2972 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") 2973 self.add_param("lpp1", 1, fortran_name="lpp(1)", allowed=[-1,1,0,2,3,9, -2,-3,4,-4], 2974 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') 2975 self.add_param("lpp2", 1, fortran_name="lpp(2)", allowed=[-1,1,0,2,3,9,4,-4], 2976 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') 2977 self.add_param("ebeam1", 6500.0, fortran_name="ebeam(1)") 2978 self.add_param("ebeam2", 6500.0, fortran_name="ebeam(2)") 2979 self.add_param("polbeam1", 0.0, fortran_name="pb1", hidden=True, 2980 comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--") 2981 self.add_param("polbeam2", 0.0, fortran_name="pb2", hidden=True, 2982 comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--") 2983 self.add_param('nb_proton1', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(1)", 2984 comment='For heavy ion physics nb of proton in the ion (for both beam but if group_subprocess was False)') 2985 self.add_param('nb_proton2', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(2)", 2986 comment='For heavy ion physics nb of proton in the ion (used for beam 2 if group_subprocess was False)') 2987 self.add_param('nb_neutron1', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(1)", 2988 comment='For heavy ion physics nb of neutron in the ion (for both beam but if group_subprocess was False)') 2989 self.add_param('nb_neutron2', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(2)", 2990 comment='For heavy ion physics nb of neutron in the ion (of beam 2 if group_subprocess was False )') 2991 self.add_param('mass_ion1', -1.0, hidden=True, fortran_name="mass_ion(1)", 2992 allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'], 2993 comment='For heavy ion physics mass in GeV of the ion (of beam 1)') 2994 self.add_param('mass_ion2', -1.0, hidden=True, fortran_name="mass_ion(2)", 2995 allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'], 2996 comment='For heavy ion physics mass in GeV of the ion (of beam 2)') 2997 2998 self.add_param("pdlabel", "nn23lo1", allowed=['lhapdf', 'cteq6_m','cteq6_l', 'cteq6l1','nn23lo', 'nn23lo1', 'nn23nlo']), 2999 self.add_param("lhaid", 230000, hidden=True) 3000 self.add_param("fixed_ren_scale", False) 3001 self.add_param("fixed_fac_scale", False) 3002 self.add_param("scale", 91.1880) 3003 self.add_param("dsqrt_q2fact1", 91.1880, fortran_name="sf1") 3004 self.add_param("dsqrt_q2fact2", 91.1880, fortran_name="sf2") 3005 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", 3006 allowed=[-1,0,1,2,3,4]) 3007 3008 # Bias module options 3009 self.add_param("bias_module", 'None', include=False) 3010 self.add_param('bias_parameters', {'__type__':1.0}, include='BIAS/bias.inc') 3011 3012 #matching 3013 self.add_param("scalefact", 1.0) 3014 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.") 3015 self.add_param("highestmult", 1, fortran_name="nhmult", hidden=True) 3016 self.add_param("ktscheme", 1, hidden=True) 3017 self.add_param("alpsfact", 1.0, hidden=True) 3018 self.add_param("chcluster", False, hidden=True) 3019 self.add_param("pdfwgt", True, hidden=True) 3020 self.add_param("asrwgtflavor", 5, hidden=True, comment = 'highest quark flavor for a_s reweighting in MLM') 3021 self.add_param("clusinfo", True, hidden=True) 3022 #format output / boost 3023 self.add_param("lhe_version", 3.0, hidden=True) 3024 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") 3025 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") 3026 self.add_param('frame_id', 6, system=True) 3027 self.add_param("event_norm", "average", allowed=['sum','average', 'unity'], 3028 include=False, sys_default='sum', hidden=True) 3029 #cut 3030 self.add_param("auto_ptj_mjj", True, hidden=True) 3031 self.add_param("bwcutoff", 15.0) 3032 self.add_param("cut_decays", False, cut='d') 3033 self.add_param("nhel", 0, include=False) 3034 #pt cut 3035 self.add_param("ptj", 20.0, cut='j') 3036 self.add_param("ptb", 0.0, cut='b') 3037 self.add_param("pta", 10.0, cut='a') 3038 self.add_param("ptl", 10.0, cut='l') 3039 self.add_param("misset", 0.0, cut='n') 3040 self.add_param("ptheavy", 0.0, cut='H', comment='this cut apply on particle heavier than 10 GeV') 3041 self.add_param("ptonium", 1.0, legacy=True) 3042 self.add_param("ptjmax", -1.0, cut='j') 3043 self.add_param("ptbmax", -1.0, cut='b') 3044 self.add_param("ptamax", -1.0, cut='a') 3045 self.add_param("ptlmax", -1.0, cut='l') 3046 self.add_param("missetmax", -1.0, cut='n') 3047 # E cut 3048 self.add_param("ej", 0.0, cut='j', hidden=True) 3049 self.add_param("eb", 0.0, cut='b', hidden=True) 3050 self.add_param("ea", 0.0, cut='a', hidden=True) 3051 self.add_param("el", 0.0, cut='l', hidden=True) 3052 self.add_param("ejmax", -1.0, cut='j', hidden=True) 3053 self.add_param("ebmax", -1.0, cut='b', hidden=True) 3054 self.add_param("eamax", -1.0, cut='a', hidden=True) 3055 self.add_param("elmax", -1.0, cut='l', hidden=True) 3056 # Eta cut 3057 self.add_param("etaj", 5.0, cut='j') 3058 self.add_param("etab", -1.0, cut='b') 3059 self.add_param("etaa", 2.5, cut='a') 3060 self.add_param("etal", 2.5, cut='l') 3061 self.add_param("etaonium", 0.6, legacy=True) 3062 self.add_param("etajmin", 0.0, cut='a') 3063 self.add_param("etabmin", 0.0, cut='b') 3064 self.add_param("etaamin", 0.0, cut='a') 3065 self.add_param("etalmin", 0.0, cut='l') 3066 # DRJJ 3067 self.add_param("drjj", 0.4, cut='jj') 3068 self.add_param("drbb", 0.0, cut='bb') 3069 self.add_param("drll", 0.4, cut='ll') 3070 self.add_param("draa", 0.4, cut='aa') 3071 self.add_param("drbj", 0.0, cut='bj') 3072 self.add_param("draj", 0.4, cut='aj') 3073 self.add_param("drjl", 0.4, cut='jl') 3074 self.add_param("drab", 0.0, cut='ab') 3075 self.add_param("drbl", 0.0, cut='bl') 3076 self.add_param("dral", 0.4, cut='al') 3077 self.add_param("drjjmax", -1.0, cut='jj') 3078 self.add_param("drbbmax", -1.0, cut='bb') 3079 self.add_param("drllmax", -1.0, cut='ll') 3080 self.add_param("draamax", -1.0, cut='aa') 3081 self.add_param("drbjmax", -1.0, cut='bj') 3082 self.add_param("drajmax", -1.0, cut='aj') 3083 self.add_param("drjlmax", -1.0, cut='jl') 3084 self.add_param("drabmax", -1.0, cut='ab') 3085 self.add_param("drblmax", -1.0, cut='bl') 3086 self.add_param("dralmax", -1.0, cut='al') 3087 # invariant mass 3088 self.add_param("mmjj", 0.0, cut='jj') 3089 self.add_param("mmbb", 0.0, cut='bb') 3090 self.add_param("mmaa", 0.0, cut='aa') 3091 self.add_param("mmll", 0.0, cut='ll') 3092 self.add_param("mmjjmax", -1.0, cut='jj') 3093 self.add_param("mmbbmax", -1.0, cut='bb') 3094 self.add_param("mmaamax", -1.0, cut='aa') 3095 self.add_param("mmllmax", -1.0, cut='ll') 3096 self.add_param("mmnl", 0.0, cut='LL') 3097 self.add_param("mmnlmax", -1.0, cut='LL') 3098 #minimum/max pt for sum of leptons 3099 self.add_param("ptllmin", 0.0, cut='ll') 3100 self.add_param("ptllmax", -1.0, cut='ll') 3101 self.add_param("xptj", 0.0, cut='jj') 3102 self.add_param("xptb", 0.0, cut='bb') 3103 self.add_param("xpta", 0.0, cut='aa') 3104 self.add_param("xptl", 0.0, cut='ll') 3105 # ordered pt jet 3106 self.add_param("ptj1min", 0.0, cut='jj') 3107 self.add_param("ptj1max", -1.0, cut='jj') 3108 self.add_param("ptj2min", 0.0, cut='jj') 3109 self.add_param("ptj2max", -1.0, cut='jj') 3110 self.add_param("ptj3min", 0.0, cut='jjj') 3111 self.add_param("ptj3max", -1.0, cut='jjj') 3112 self.add_param("ptj4min", 0.0, cut='j'*4) 3113 self.add_param("ptj4max", -1.0, cut='j'*4) 3114 self.add_param("cutuse", 0, cut='jj') 3115 # ordered pt lepton 3116 self.add_param("ptl1min", 0.0, cut='l'*2) 3117 self.add_param("ptl1max", -1.0, cut='l'*2) 3118 self.add_param("ptl2min", 0.0, cut='l'*2) 3119 self.add_param("ptl2max", -1.0, cut='l'*2) 3120 self.add_param("ptl3min", 0.0, cut='l'*3) 3121 self.add_param("ptl3max", -1.0, cut='l'*3) 3122 self.add_param("ptl4min", 0.0, cut='l'*4) 3123 self.add_param("ptl4max", -1.0, cut='l'*4) 3124 # Ht sum of jets 3125 self.add_param("htjmin", 0.0, cut='j'*2) 3126 self.add_param("htjmax", -1.0, cut='j'*2) 3127 self.add_param("ihtmin", 0.0, cut='J'*2) 3128 self.add_param("ihtmax", -1.0, cut='J'*2) 3129 self.add_param("ht2min", 0.0, cut='J'*3) 3130 self.add_param("ht3min", 0.0, cut='J'*3) 3131 self.add_param("ht4min", 0.0, cut='J'*4) 3132 self.add_param("ht2max", -1.0, cut='J'*3) 3133 self.add_param("ht3max", -1.0, cut='J'*3) 3134 self.add_param("ht4max", -1.0, cut='J'*4) 3135 # photon isolation 3136 self.add_param("ptgmin", 0.0, cut='aj') 3137 self.add_param("r0gamma", 0.4, hidden=True) 3138 self.add_param("xn", 1.0, hidden=True) 3139 self.add_param("epsgamma", 1.0, hidden=True) 3140 self.add_param("isoem", True, hidden=True) 3141 self.add_param("xetamin", 0.0, cut='jj') 3142 self.add_param("deltaeta", 0.0, cut='j'*2) 3143 self.add_param("ktdurham", -1.0, fortran_name="kt_durham", cut='j') 3144 self.add_param("dparameter", 0.4, fortran_name="d_parameter", cut='j') 3145 self.add_param("ptlund", -1.0, fortran_name="pt_lund", cut='j') 3146 self.add_param("pdgs_for_merging_cut", [21, 1, 2, 3, 4, 5, 6], hidden=True) 3147 self.add_param("maxjetflavor", 4) 3148 self.add_param("xqcut", 0.0, cut=True) 3149 self.add_param("use_syst", True) 3150 self.add_param('systematics_program', 'systematics', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics, syscalc') 3151 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.') 3152 3153 self.add_param("sys_scalefact", "0.5 1 2", include=False, hidden=True) 3154 self.add_param("sys_alpsfact", "None", include=False, hidden=True) 3155 self.add_param("sys_matchscale", "auto", include=False, hidden=True) 3156 self.add_param("sys_pdf", "errorset", include=False, hidden=True) 3157 self.add_param("sys_scalecorrelation", -1, include=False, hidden=True) 3158 3159 #parameter not in the run_card by default 3160 self.add_param('gridrun', False, hidden=True) 3161 self.add_param('fixed_couplings', True, hidden=True) 3162 self.add_param('mc_grouped_subproc', True, hidden=True) 3163 self.add_param('xmtcentral', 0.0, hidden=True, fortran_name="xmtc") 3164 self.add_param('d', 1.0, hidden=True) 3165 self.add_param('gseed', 0, hidden=True, include=False) 3166 self.add_param('issgridfile', '', hidden=True) 3167 #job handling of the survey/ refine 3168 self.add_param('job_strategy', 0, hidden=True, include=False, allowed=[0,1,2], comment='see appendix of 1507.00020 (page 26)') 3169 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') 3170 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') 3171 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.") 3172 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.") 3173 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") 3174 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)") 3175 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") 3176 #hel recycling 3177 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--') 3178 self.add_param('hel_filtering', True, hidden=True, include=False, comment='filter in advance the zero helicities when doing helicity per helicity optimization.') 3179 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.') 3180 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.') 3181 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") 3182 self.add_param('global_flag', '-O', include=False, hidden=True, comment='global fortran compilation flag, suggestion -fbound-check') 3183 self.add_param('aloha_flag', '', include=False, hidden=True, comment='global fortran compilation flag, suggestion: -ffast-math') 3184 self.add_param('matrix_flag', '', include=False, hidden=True, comment='global fortran compilation flag, suggestion: -O3') 3185 3186 # parameter allowing to define simple cut via the pdg 3187 # Special syntax are related to those. (can not be edit directly) 3188 self.add_param('pt_min_pdg',{'__type__':0.}, include=False, cut=True) 3189 self.add_param('pt_max_pdg',{'__type__':0.}, include=False, cut=True) 3190 self.add_param('E_min_pdg',{'__type__':0.}, include=False, hidden=True,cut=True) 3191 self.add_param('E_max_pdg',{'__type__':0.}, include=False, hidden=True,cut=True) 3192 self.add_param('eta_min_pdg',{'__type__':0.}, include=False,cut=True) 3193 self.add_param('eta_max_pdg',{'__type__':0.}, include=False,cut=True) 3194 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True) 3195 self.add_param('mxx_only_part_antipart', {'default':False}, include=False) 3196 3197 self.add_param('pdg_cut',[0], system=True) # store which PDG are tracked 3198 self.add_param('ptmin4pdg',[0.], system=True) # store pt min 3199 self.add_param('ptmax4pdg',[-1.], system=True) 3200 self.add_param('Emin4pdg',[0.], system=True) # store pt min 3201 self.add_param('Emax4pdg',[-1.], system=True) 3202 self.add_param('etamin4pdg',[0.], system=True) # store pt min 3203 self.add_param('etamax4pdg',[-1.], system=True) 3204 self.add_param('mxxmin4pdg',[-1.], system=True) 3205 self.add_param('mxxpart_antipart', [False], system=True)
3206 3207 3208
3209 - def check_validity(self):
3210 """ """ 3211 3212 super(RunCardLO, self).check_validity() 3213 3214 #Make sure that nhel is only either 0 (i.e. no MC over hel) or 3215 #1 (MC over hel with importance sampling). In particular, it can 3216 #no longer be > 1. 3217 if 'nhel' not in self: 3218 raise InvalidRunCard("Parameter nhel is not defined in the run_card.") 3219 if self['nhel'] not in [1,0]: 3220 raise InvalidRunCard("Parameter nhel can only be '0' or '1', "+\ 3221 "not %s." % self['nhel']) 3222 if int(self['maxjetflavor']) > 6: 3223 raise InvalidRunCard('maxjetflavor should be lower than 5! (6 is partly supported)') 3224 3225 if len(self['pdgs_for_merging_cut']) > 1000: 3226 raise InvalidRunCard("The number of elements in "+\ 3227 "'pdgs_for_merging_cut' should not exceed 1000.") 3228 3229 # some cut need to be deactivated in presence of isolation 3230 if self['ptgmin'] > 0: 3231 if self['pta'] > 0: 3232 logger.warning('pta cut discarded since photon isolation is used') 3233 self['pta'] = 0.0 3234 if self['draj'] > 0: 3235 logger.warning('draj cut discarded since photon isolation is used') 3236 self['draj'] = 0.0 3237 3238 # special treatment for gridpack use the gseed instead of the iseed 3239 if self['gridrun']: 3240 self['iseed'] = self['gseed'] 3241 3242 #Some parameter need to be fixed when using syscalc 3243 if self['use_syst']: 3244 if self['scalefact'] != 1.0: 3245 logger.warning('Since use_syst=T, We change the value of \'scalefact\' to 1') 3246 self['scalefact'] = 1.0 3247 3248 # CKKW Treatment 3249 if self['ickkw'] > 0: 3250 if self['ickkw'] != 1: 3251 logger.critical('ickkw >1 is pure alpha and only partly implemented.') 3252 import madgraph.interface.extended_cmd as basic_cmd 3253 answer = basic_cmd.smart_input('Do you really want to continue', allow_arg=['y','n'], default='n') 3254 if answer !='y': 3255 raise InvalidRunCard('ickkw>1 is still in alpha') 3256 if self['use_syst']: 3257 # some additional parameter need to be fixed for Syscalc + matching 3258 if self['alpsfact'] != 1.0: 3259 logger.warning('Since use_syst=T, We change the value of \'alpsfact\' to 1') 3260 self['alpsfact'] =1.0 3261 if self['maxjetflavor'] == 6: 3262 raise InvalidRunCard('maxjetflavor at 6 is NOT supported for matching!') 3263 if self['ickkw'] == 2: 3264 # add warning if ckkw selected but the associate parameter are empty 3265 self.get_default('highestmult', log_level=20) 3266 self.get_default('issgridfile', 'issudgrid.dat', log_level=20) 3267 if self['xqcut'] > 0: 3268 if self['ickkw'] == 0: 3269 logger.error('xqcut>0 but ickkw=0. Potentially not fully consistent setup. Be carefull') 3270 time.sleep(5) 3271 if self['drjj'] != 0: 3272 if 'drjj' in self.user_set: 3273 logger.warning('Since icckw>0, We change the value of \'drjj\' to 0') 3274 self['drjj'] = 0 3275 if self['drjl'] != 0: 3276 if 'drjl' in self.user_set: 3277 logger.warning('Since icckw>0, We change the value of \'drjl\' to 0') 3278 self['drjl'] = 0 3279 if not self['auto_ptj_mjj']: 3280 if self['mmjj'] > self['xqcut']: 3281 logger.warning('mmjj > xqcut (and auto_ptj_mjj = F). MMJJ set to 0') 3282 self['mmjj'] = 0.0 3283 3284 # check validity of the pdf set 3285 if self['pdlabel'] == 'lhapdf': 3286 #add warning if lhaid not define 3287 self.get_default('lhaid', log_level=20) 3288 3289 # if heavy ion mode use for one beam, forbis lpp!=1 3290 if self['lpp1'] not in [1,2]: 3291 if self['nb_proton1'] !=1 or self['nb_neutron1'] !=0: 3292 raise InvalidRunCard( "Heavy ion mode is only supported for lpp1=1/2") 3293 if self['lpp2'] not in [1,2]: 3294 if self['nb_proton2'] !=1 or self['nb_neutron2'] !=0: 3295 raise InvalidRunCard( "Heavy ion mode is only supported for lpp2=1/2") 3296 3297 # check if lpp = 3298 for i in [1,2]: 3299 if abs(self['lpp%s' % i ]) in [3,4] and self['dsqrt_q2fact%s'%i] == 91.188: 3300 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) 3301 time.sleep(5) 3302 3303 if abs(self['lpp%s' % i ]) == 2 and self['dsqrt_q2fact%s'%i] == 91.188: 3304 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) 3305 time.sleep(5) 3306 3307 # if both lpp1/2 are on PA mode -> force fixed factorization scale 3308 if abs(self['lpp1']) in [2, 3,4] and abs(self['lpp2']) in [2, 3,4] and not self['fixed_fac_scale']: 3309 raise InvalidRunCard("Having both beam in elastic photon mode requires fixed_fac_scale to be on True [since this is use as cutoff]") 3310 3311 if six.PY2 and self['hel_recycling']: 3312 self['hel_recycling'] = False 3313 logger.warning("""Helicity recycling optimization requires Python3. This optimzation is therefore deactivated automatically. 3314 In general this optimization speed up the computation be a factor of two.""") 3315 3316 3317 # check that ebeam is bigger than the associated mass. 3318 for i in [1,2]: 3319 if self['lpp%s' % i ] not in [1,2]: 3320 continue 3321 if self['mass_ion%i' % i] == -1: 3322 if self['ebeam%i' % i] < 0.938: 3323 if self['ebeam%i' %i] == 0: 3324 logger.warning("At rest proton mode set: Energy beam set to 0.938") 3325 self.set('ebeam%i' %i, 0.938) 3326 else: 3327 raise InvalidRunCard("Energy for beam %i lower than proton mass. Please fix this") 3328 elif self['ebeam%i' % i] < self['mass_ion%i' % i]: 3329 if self['ebeam%i' %i] == 0: 3330 logger.warning("At rest ion mode set: Energy beam set to %s" % self['mass_ion%i' % i]) 3331 self.set('ebeam%i' %i, self['mass_ion%i' % i]) 3332 3333 3334 # check the tmin_for_channel is negative 3335 if self['tmin_for_channel'] == 0: 3336 raise InvalidRunCard('tmin_for_channel can not be set to 0.') 3337 elif self['tmin_for_channel'] > 0: 3338 logger.warning('tmin_for_channel should be negative. Will be using -%f instead' % self['tmin_for_channel']) 3339 self.set('tmin_for_channel', -self['tmin_for_channel'])
3340 3341 3342 3343
3345 3346 # polarization 3347 self['frame_id'] = sum(2**(n) for n in self['me_frame']) 3348 3349 # set the pdg_for_cut fortran parameter 3350 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys()) + 3351 list(self['e_min_pdg'].keys()) +list(self['e_max_pdg'].keys()) + 3352 list(self['eta_min_pdg'].keys()) +list(self['eta_max_pdg'].keys())+ 3353 list(self['mxx_min_pdg'].keys()) + list(self['mxx_only_part_antipart'].keys())) 3354 pdg_to_cut.discard('__type__') 3355 pdg_to_cut.discard('default') 3356 if len(pdg_to_cut)>25: 3357 raise Exception("Maximum 25 different pdgs are allowed for pdg specific cut") 3358 3359 if any(int(pdg)<0 for pdg in pdg_to_cut): 3360 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes') 3361 raise MadGraph5Error('Some PDG specific cuts are defined with negative pdg code') 3362 3363 3364 if any(pdg in pdg_to_cut for pdg in [1,2,3,4,5,21,22,11,13,15]): 3365 raise Exception("Can not use PDG related cut for light quark/b quark/lepton/gluon/photon") 3366 3367 if pdg_to_cut: 3368 self['pdg_cut'] = list(pdg_to_cut) 3369 self['ptmin4pdg'] = [] 3370 self['Emin4pdg'] = [] 3371 self['etamin4pdg'] =[] 3372 self['ptmax4pdg'] = [] 3373 self['Emax4pdg'] = [] 3374 self['etamax4pdg'] =[] 3375 self['mxxmin4pdg'] =[] 3376 self['mxxpart_antipart'] = [] 3377 for pdg in self['pdg_cut']: 3378 for var in ['pt','e','eta', 'Mxx']: 3379 for minmax in ['min', 'max']: 3380 if var in ['Mxx'] and minmax =='max': 3381 continue 3382 new_var = '%s%s4pdg' % (var, minmax) 3383 old_var = '%s_%s_pdg' % (var, minmax) 3384 default = 0. if minmax=='min' else -1. 3385 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default) 3386 #special for mxx_part_antipart 3387 old_var = 'mxx_only_part_antipart' 3388 new_var = 'mxxpart_antipart' 3389 if 'default' in self[old_var]: 3390 default = self[old_var]['default'] 3391 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default) 3392 else: 3393 if str(pdg) not in self[old_var]: 3394 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg)) 3395 self[new_var].append(self[old_var][str(pdg)]) 3396 else: 3397 self['pdg_cut'] = [0] 3398 self['ptmin4pdg'] = [0.] 3399 self['Emin4pdg'] = [0.] 3400 self['etamin4pdg'] =[0.] 3401 self['ptmax4pdg'] = [-1.] 3402 self['Emax4pdg'] = [-1.] 3403 self['etamax4pdg'] =[-1.] 3404 self['mxxmin4pdg'] =[0.] 3405 self['mxxpart_antipart'] = [False]
3406 3407 3408
3409 - def create_default_for_process(self, proc_characteristic, history, proc_def):
3410 """Rules 3411 process 1->N all cut set on off. 3412 loop_induced -> MC over helicity 3413 e+ e- beam -> lpp:0 ebeam:500 3414 p p beam -> set maxjetflavor automatically 3415 more than one multiplicity: ickkw=1 xqcut=30 use_syst=F 3416 """ 3417 3418 3419 if proc_characteristic['loop_induced']: 3420 self['nhel'] = 1 3421 self['pdgs_for_merging_cut'] = proc_characteristic['colored_pdgs'] 3422 3423 if proc_characteristic['ninitial'] == 1: 3424 #remove all cut 3425 self.remove_all_cut() 3426 self['use_syst'] = False 3427 else: 3428 # check for beam_id 3429 # check for beam_id 3430 beam_id = set() 3431 beam_id_split = [set(), set()] 3432 for proc in proc_def: 3433 for oneproc in proc: 3434 for i,leg in enumerate(oneproc['legs']): 3435 if not leg['state']: 3436 beam_id_split[i].add(leg['id']) 3437 beam_id.add(leg['id']) 3438 3439 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]): 3440 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7]) 3441 self['maxjetflavor'] = maxjetflavor 3442 self['asrwgtflavor'] = maxjetflavor 3443 3444 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]): 3445 # check for e p collision 3446 if any(id in beam_id for id in [11,-11,13,-13]): 3447 self.display_block.append('beam_pol') 3448 if any(id in beam_id_split[0] for id in [11,-11,13,-13]): 3449 self['lpp1'] = 0 3450 self['lpp2'] = 1 3451 self['ebeam1'] = '1k' 3452 self['ebeam2'] = '6500' 3453 else: 3454 self['lpp1'] = 1 3455 self['lpp2'] = 0 3456 self['ebeam1'] = '6500' 3457 self['ebeam2'] = '1k' 3458 3459 elif any(id in beam_id for id in [11,-11,13,-13]): 3460 self['lpp1'] = 0 3461 self['lpp2'] = 0 3462 self['ebeam1'] = 500 3463 self['ebeam2'] = 500 3464 self['use_syst'] = False 3465 if set([ abs(i) for i in beam_id_split[0]]) == set([ abs(i) for i in beam_id_split[1]]): 3466 self.display_block.append('ecut') 3467 self.display_block.append('beam_pol') 3468 else: 3469 self['lpp1'] = 0 3470 self['lpp2'] = 0 3471 self['use_syst'] = False 3472 self.display_block.append('beam_pol') 3473 self.display_block.append('ecut') 3474 3475 # automatic polarisation of the beam if neutrino beam 3476 if any(id in beam_id for id in [12,-12,14,-14,16,-16]): 3477 self.display_block.append('beam_pol') 3478 if any(id in beam_id_split[0] for id in [12,14,16]): 3479 self['lpp1'] = 0 3480 self['ebeam1'] = '1k' 3481 self['polbeam1'] = -100 3482 if not all(id in [12,14,16] for id in beam_id_split[0]): 3483 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1]. %s') 3484 elif any(id in beam_id_split[0] for id in [-12,-14,-16]): 3485 self['lpp1'] = 0 3486 self['ebeam1'] = '1k' 3487 self['polbeam1'] = 100 3488 if not all(id in [-12,-14,-16] for id in beam_id_split[0]): 3489 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1].') 3490 if any(id in beam_id_split[1] for id in [12,14,16]): 3491 self['lpp2'] = 0 3492 self['ebeam2'] = '1k' 3493 self['polbeam2'] = -100 3494 if not all(id in [12,14,16] for id in beam_id_split[1]): 3495 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].') 3496 if any(id in beam_id_split[1] for id in [-12,-14,-16]): 3497 self['lpp2'] = 0 3498 self['ebeam2'] = '1k' 3499 self['polbeam2'] = 100 3500 if not all(id in [-12,-14,-16] for id in beam_id_split[1]): 3501 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].') 3502 3503 # Check if need matching 3504 min_particle = 99 3505 max_particle = 0 3506 for proc in proc_def: 3507 min_particle = min(len(proc[0]['legs']), min_particle) 3508 max_particle = max(len(proc[0]['legs']), max_particle) 3509 if min_particle != max_particle: 3510 #take one of the process with min_particle 3511 for procmin in proc_def: 3512 if len(procmin[0]['legs']) != min_particle: 3513 continue 3514 else: 3515 idsmin = [l['id'] for l in procmin[0]['legs']] 3516 break 3517 matching = False 3518 for procmax in proc_def: 3519 if len(procmax[0]['legs']) != max_particle: 3520 continue 3521 idsmax = [l['id'] for l in procmax[0]['legs']] 3522 for i in idsmin: 3523 if i not in idsmax: 3524 continue 3525 else: 3526 idsmax.remove(i) 3527 for j in idsmax: 3528 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]: 3529 break 3530 else: 3531 # all are jet => matching is ON 3532 matching=True 3533 break 3534 3535 if matching: 3536 self['ickkw'] = 1 3537 self['xqcut'] = 30 3538 #self['use_syst'] = False 3539 self['drjj'] = 0 3540 self['drjl'] = 0 3541 self['sys_alpsfact'] = "0.5 1 2" 3542 self['systematics_arguments'].append('--alps=0.5,1,2') 3543 self.display_block.append('mlm') 3544 self.display_block.append('ckkw') 3545 self['dynamical_scale_choice'] = -1 3546 3547 3548 # For interference module, the systematics are wrong. 3549 # automatically set use_syst=F and set systematics_program=none 3550 no_systematics = False 3551 interference = False 3552 for proc in proc_def: 3553 for oneproc in proc: 3554 if '^2' in oneproc.nice_string(): 3555 interference = True 3556 break 3557 else: 3558 continue 3559 break 3560 3561 3562 if interference or no_systematics: 3563 self['use_syst'] = False 3564 self['systematics_program'] = 'none' 3565 if interference: 3566 self['dynamical_scale_choice'] = 3 3567 self['sde_strategy'] = 2 3568 3569 # set default integration strategy 3570 # interference case is already handle above 3571 # here pick strategy 2 if only one QCD color flow 3572 # and for pure multi-jet case 3573 if proc_characteristic['single_color']: 3574 self['sde_strategy'] = 2 3575 else: 3576 # check if multi-jet j 3577 is_multijet = True 3578 jet_id = [21] + list(range(1, self['maxjetflavor']+1)) 3579 for proc in proc_def: 3580 if any(abs(j.get('id')) not in jet_id for j in proc[0]['legs']): 3581 is_multijet = False 3582 break 3583 if is_multijet: 3584 self['sde_strategy'] = 2 3585 3586 # if polarization is used, set the choice of the frame in the run_card 3587 # But only if polarization is used for massive particles 3588 for plist in proc_def: 3589 for proc in plist: 3590 for l in proc.get('legs') + proc.get('legs_with_decays'): 3591 if l.get('polarization'): 3592 model = proc.get('model') 3593 particle = model.get_particle(l.get('id')) 3594 if particle.get('mass').lower() != 'zero': 3595 self.display_block.append('frame') 3596 break 3597 else: 3598 continue 3599 break 3600 else: 3601 continue 3602 break 3603 3604 if 'MLM' in proc_characteristic['limitations']: 3605 if self['dynamical_scale_choice'] == -1: 3606 self['dynamical_scale_choice'] = 3 3607 if self['ickkw'] == 1: 3608 logger.critical("MLM matching/merging not compatible with the model! You need to use another method to remove the double counting!") 3609 self['ickkw'] = 0 3610 3611 # define class of particles present to hide all the cuts associated to 3612 # not present class 3613 cut_class = collections.defaultdict(int) 3614 for proc in proc_def: 3615 for oneproc in proc: 3616 one_proc_cut = collections.defaultdict(int) 3617 ids = oneproc.get_final_ids_after_decay() 3618 if oneproc['decay_chains']: 3619 cut_class['d'] = 1 3620 for pdg in ids: 3621 if pdg == 22: 3622 one_proc_cut['a'] +=1 3623 elif abs(pdg) <= self['maxjetflavor']: 3624 one_proc_cut['j'] += 1 3625 one_proc_cut['J'] += 1 3626 elif abs(pdg) <= 5: 3627 one_proc_cut['b'] += 1 3628 one_proc_cut['J'] += 1 3629 elif abs(pdg) in [11,13,15]: 3630 one_proc_cut['l'] += 1 3631 one_proc_cut['L'] += 1 3632 elif abs(pdg) in [12,14,16]: 3633 one_proc_cut['n'] += 1 3634 one_proc_cut['L'] += 1 3635 elif str(oneproc.get('model').get_particle(pdg)['mass']) != 'ZERO': 3636 one_proc_cut['H'] += 1 3637 3638 for key, nb in one_proc_cut.items(): 3639 cut_class[key] = max(cut_class[key], nb) 3640 self.cut_class = dict(cut_class) 3641 self.cut_class[''] = True #avoid empty
3642
3643 - def write(self, output_file, template=None, python_template=False, 3644 **opt):
3645 """Write the run_card in output_file according to template 3646 (a path to a valid run_card)""" 3647 3648 if not template: 3649 if not MADEVENT: 3650 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards', 3651 'run_card.dat') 3652 python_template = True 3653 else: 3654 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat') 3655 python_template = False 3656 3657 3658 hid_lines = {'default':True}#collections.defaultdict(itertools.repeat(True).next) 3659 if isinstance(output_file, str): 3660 if 'default' in output_file: 3661 if self.cut_class: 3662 hid_lines['default'] = False 3663 for key in self.cut_class: 3664 nb = self.cut_class[key] 3665 for i in range(1,nb+1): 3666 hid_lines[key*i] = True 3667 for k1,k2 in ['bj', 'bl', 'al', 'jl', 'ab', 'aj']: 3668 if self.cut_class.get(k1) and self.cut_class.get(k2): 3669 hid_lines[k1+k2] = True 3670 3671 super(RunCardLO, self).write(output_file, template=template, 3672 python_template=python_template, 3673 template_options=hid_lines, 3674 **opt)
3675
3676 3677 -class InvalidMadAnalysis5Card(InvalidCmd):
3678 pass
3679
3680 -class MadAnalysis5Card(dict):
3681 """ A class to store a MadAnalysis5 card. Very basic since it is basically 3682 free format.""" 3683 3684 _MG5aMC_escape_tag = '@MG5aMC' 3685 3686 _default_hadron_inputs = ['*.hepmc', '*.hep', '*.stdhep', '*.lhco','*.root'] 3687 _default_parton_inputs = ['*.lhe'] 3688 _skip_analysis = False 3689 3690 @classmethod
3691 - def events_can_be_reconstructed(cls, file_path):
3692 """ Checks from the type of an event file whether it can be reconstructed or not.""" 3693 return not (file_path.endswith('.lhco') or file_path.endswith('.lhco.gz') or \ 3694 file_path.endswith('.root') or file_path.endswith('.root.gz'))
3695 3696 @classmethod
3697 - def empty_analysis(cls):
3698 """ A method returning the structure of an empty analysis """ 3699 return {'commands':[], 3700 'reconstructions':[]}
3701 3702 @classmethod
3703 - def empty_reconstruction(cls):
3704 """ A method returning the structure of an empty reconstruction """ 3705 return {'commands':[], 3706 'reco_output':'lhe'}
3707
3708 - def default_setup(self):
3709 """define the default value""" 3710 self['mode'] = 'parton' 3711 self['inputs'] = [] 3712 # None is the default stdout level, it will be set automatically by MG5aMC 3713 self['stdout_lvl'] = None 3714 # These two dictionaries are formated as follows: 3715 # {'analysis_name': 3716 # {'reconstructions' : ['associated_reconstructions_name']} 3717 # {'commands':['analysis command lines here']} } 3718 # with values being of the form of the empty_analysis() attribute 3719 # of this class and some other property could be added to this dictionary 3720 # in the future. 3721 self['analyses'] = {} 3722 # The recasting structure contains on set of commands and one set of 3723 # card lines. 3724 self['recasting'] = {'commands':[],'card':[]} 3725 # Add the default trivial reconstruction to use an lhco input 3726 # This is just for the structure 3727 self['reconstruction'] = {'lhco_input': 3728 MadAnalysis5Card.empty_reconstruction(), 3729 'root_input': 3730 MadAnalysis5Card.empty_reconstruction()} 3731 self['reconstruction']['lhco_input']['reco_output']='lhco' 3732 self['reconstruction']['root_input']['reco_output']='root' 3733 3734 # Specify in which order the analysis/recasting were specified 3735 self['order'] = []
3736
3737 - def __init__(self, finput=None,mode=None):
3738 if isinstance(finput, self.__class__): 3739 dict.__init__(self, finput) 3740 assert list(finput.__dict__.keys()) 3741 for key in finput.__dict__: 3742 setattr(self, key, copy.copy(getattr(finput, key)) ) 3743 return 3744 else: 3745 dict.__init__(self) 3746 3747 # Initialize it with all the default value 3748 self.default_setup() 3749 if not mode is None: 3750 self['mode']=mode 3751 3752 # if input is define read that input 3753 if isinstance(finput, (file, str, StringIO.StringIO)): 3754 self.read(finput, mode=mode)
3755
3756 - def read(self, input, mode=None):
3757 """ Read an MA5 card""" 3758 3759 if mode not in [None,'parton','hadron']: 3760 raise MadGraph5Error('A MadAnalysis5Card can be read online the modes'+ 3761 "'parton' or 'hadron'") 3762 card_mode = mode 3763 3764 if isinstance(input, (file, StringIO.StringIO)): 3765 input_stream = input 3766 elif isinstance(input, str): 3767 if not os.path.isfile(input): 3768 raise InvalidMadAnalysis5Card("Cannot read the MadAnalysis5 card."+\ 3769 "File '%s' not found."%input) 3770 if mode is None and 'hadron' in input: 3771 card_mode = 'hadron' 3772 input_stream = open(input,'r') 3773 else: 3774 raise MadGraph5Error('Incorrect input for the read function of'+\ 3775 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(input))) 3776 3777 # Reinstate default values 3778 self.__init__() 3779 current_name = 'default' 3780 current_type = 'analyses' 3781 for line in input_stream: 3782 # Skip comments for now 3783 if line.startswith('#'): 3784 continue 3785 if line.endswith('\n'): 3786 line = line[:-1] 3787 if line.strip()=='': 3788 continue 3789 if line.startswith(self._MG5aMC_escape_tag): 3790 try: 3791 option,value = line[len(self._MG5aMC_escape_tag):].split('=') 3792 value = value.strip() 3793 except ValueError: 3794 option = line[len(self._MG5aMC_escape_tag):] 3795 option = option.strip() 3796 3797 if option=='inputs': 3798 self['inputs'].extend([v.strip() for v in value.split(',')]) 3799 3800 elif option == 'skip_analysis': 3801 self._skip_analysis = True 3802 3803 elif option=='stdout_lvl': 3804 try: # It is likely an int 3805 self['stdout_lvl']=int(value) 3806 except ValueError: 3807 try: # Maybe the user used something like 'logging.INFO' 3808 self['stdout_lvl']=eval(value) 3809 except: 3810 try: 3811 self['stdout_lvl']=eval('logging.%s'%value) 3812 except: 3813 raise InvalidMadAnalysis5Card( 3814 "MA5 output level specification '%s' is incorrect."%str(value)) 3815 3816 elif option=='analysis_name': 3817 current_type = 'analyses' 3818 current_name = value 3819 if current_name in self[current_type]: 3820 raise InvalidMadAnalysis5Card( 3821 "Analysis '%s' already defined in MadAnalysis5 card"%current_name) 3822 else: 3823 self[current_type][current_name] = MadAnalysis5Card.empty_analysis() 3824 3825 elif option=='set_reconstructions': 3826 try: 3827 reconstructions = eval(value) 3828 if not isinstance(reconstructions, list): 3829 raise 3830 except: 3831 raise InvalidMadAnalysis5Card("List of reconstructions"+\ 3832 " '%s' could not be parsed in MadAnalysis5 card."%value) 3833 if current_type!='analyses' and current_name not in self[current_type]: 3834 raise InvalidMadAnalysis5Card("A list of reconstructions"+\ 3835 "can only be defined in the context of an "+\ 3836 "analysis in a MadAnalysis5 card.") 3837 self[current_type][current_name]['reconstructions']=reconstructions 3838 continue 3839 3840 elif option=='reconstruction_name': 3841 current_type = 'reconstruction' 3842 current_name = value 3843 if current_name in self[current_type]: 3844 raise InvalidMadAnalysis5Card( 3845 "Reconstruction '%s' already defined in MadAnalysis5 hadron card"%current_name) 3846 else: 3847 self[current_type][current_name] = MadAnalysis5Card.empty_reconstruction() 3848 3849 elif option=='reco_output': 3850 if current_type!='reconstruction' or current_name not in \ 3851 self['reconstruction']: 3852 raise InvalidMadAnalysis5Card( 3853 "Option '%s' is only available within the definition of a reconstruction"%option) 3854 if not value.lower() in ['lhe','root']: 3855 raise InvalidMadAnalysis5Card( 3856 "Option '%s' can only take the values 'lhe' or 'root'"%option) 3857 self['reconstruction'][current_name]['reco_output'] = value.lower() 3858 3859 elif option.startswith('recasting'): 3860 current_type = 'recasting' 3861 try: 3862 current_name = option.split('_')[1] 3863 except: 3864 raise InvalidMadAnalysis5Card('Malformed MA5 recasting option %s.'%option) 3865 if len(self['recasting'][current_name])>0: 3866 raise InvalidMadAnalysis5Card( 3867 "Only one recasting can be defined in MadAnalysis5 hadron card") 3868 3869 else: 3870 raise InvalidMadAnalysis5Card( 3871 "Unreckognized MG5aMC instruction in MadAnalysis5 card: '%s'"%option) 3872 3873 if option in ['analysis_name','reconstruction_name'] or \ 3874 option.startswith('recasting'): 3875 self['order'].append((current_type,current_name)) 3876 continue 3877 3878 # Add the default analysis if needed since the user does not need 3879 # to specify it. 3880 if current_name == 'default' and current_type == 'analyses' and\ 3881 'default' not in self['analyses']: 3882 self['analyses']['default'] = MadAnalysis5Card.empty_analysis() 3883 self['order'].append(('analyses','default')) 3884 3885 if current_type in ['recasting']: 3886 self[current_type][current_name].append(line) 3887 elif current_type in ['reconstruction']: 3888 self[current_type][current_name]['commands'].append(line) 3889 elif current_type in ['analyses']: 3890 self[current_type][current_name]['commands'].append(line) 3891 3892 if 'reconstruction' in self['analyses'] or len(self['recasting']['card'])>0: 3893 if mode=='parton': 3894 raise InvalidMadAnalysis5Card( 3895 "A parton MadAnalysis5 card cannot specify a recombination or recasting.") 3896 card_mode = 'hadron' 3897 elif mode is None: 3898 card_mode = 'parton' 3899 3900 self['mode'] = card_mode 3901 if self['inputs'] == []: 3902 if self['mode']=='hadron': 3903 self['inputs'] = self._default_hadron_inputs 3904 else: 3905 self['inputs'] = self._default_parton_inputs 3906 3907 # Make sure at least one reconstruction is specified for each hadron 3908 # level analysis and that it exists. 3909 if self['mode']=='hadron': 3910 for analysis_name, analysis in self['analyses'].items(): 3911 if len(analysis['reconstructions'])==0: 3912 raise InvalidMadAnalysis5Card('Hadron-level analysis '+\ 3913 "'%s' is not specified any reconstruction(s)."%analysis_name) 3914 if any(reco not in self['reconstruction'] for reco in \ 3915 analysis['reconstructions']): 3916 raise InvalidMadAnalysis5Card('A reconstructions specified in'+\ 3917 " analysis '%s' is not defined."%analysis_name)
3918
3919 - def write(self, output):
3920 """ Write an MA5 card.""" 3921 3922 if isinstance(output, (file, StringIO.StringIO)): 3923 output_stream = output 3924 elif isinstance(output, str): 3925 output_stream = open(output,'w') 3926 else: 3927 raise MadGraph5Error('Incorrect input for the write function of'+\ 3928 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(output))) 3929 3930 output_lines = [] 3931 if self._skip_analysis: 3932 output_lines.append('%s skip_analysis'%self._MG5aMC_escape_tag) 3933 output_lines.append('%s inputs = %s'%(self._MG5aMC_escape_tag,','.join(self['inputs']))) 3934 if not self['stdout_lvl'] is None: 3935 output_lines.append('%s stdout_lvl=%s'%(self._MG5aMC_escape_tag,self['stdout_lvl'])) 3936 for definition_type, name in self['order']: 3937 3938 if definition_type=='analyses': 3939 output_lines.append('%s analysis_name = %s'%(self._MG5aMC_escape_tag,name)) 3940 output_lines.append('%s set_reconstructions = %s'%(self._MG5aMC_escape_tag, 3941 str(self['analyses'][name]['reconstructions']))) 3942 elif definition_type=='reconstruction': 3943 output_lines.append('%s reconstruction_name = %s'%(self._MG5aMC_escape_tag,name)) 3944 elif definition_type=='recasting': 3945 output_lines.append('%s recasting_%s'%(self._MG5aMC_escape_tag,name)) 3946 3947 if definition_type in ['recasting']: 3948 output_lines.extend(self[definition_type][name]) 3949 elif definition_type in ['reconstruction']: 3950 output_lines.append('%s reco_output = %s'%(self._MG5aMC_escape_tag, 3951 self[definition_type][name]['reco_output'])) 3952 output_lines.extend(self[definition_type][name]['commands']) 3953 elif definition_type in ['analyses']: 3954 output_lines.extend(self[definition_type][name]['commands']) 3955 3956 output_stream.write('\n'.join(output_lines)) 3957 3958 return
3959
3960 - def get_MA5_cmds(self, inputs_arg, submit_folder, run_dir_path=None, 3961 UFO_model_path=None, run_tag=''):
3962 """ Returns a list of tuples ('AnalysisTag',['commands']) specifying 3963 the commands of the MadAnalysis runs required from this card. 3964 At parton-level, the number of such commands is the number of analysis 3965 asked for. In the future, the idea is that the entire card can be 3966 processed in one go from MA5 directly.""" 3967 3968 if isinstance(inputs_arg, list): 3969 inputs = inputs_arg 3970 elif isinstance(inputs_arg, str): 3971 inputs = [inputs_arg] 3972 else: 3973 raise MadGraph5Error("The function 'get_MA5_cmds' can only take "+\ 3974 " a string or a list for the argument 'inputs_arg'") 3975 3976 if len(inputs)==0: 3977 raise MadGraph5Error("The function 'get_MA5_cmds' must have "+\ 3978 " at least one input specified'") 3979 3980 if run_dir_path is None: 3981 run_dir_path = os.path.dirname(inputs_arg) 3982 3983 cmds_list = [] 3984 3985 UFO_load = [] 3986 # first import the UFO if provided 3987 if UFO_model_path: 3988 UFO_load.append('import %s'%UFO_model_path) 3989 3990 def get_import(input, type=None): 3991 """ Generates the MA5 import commands for that event file. """ 3992 dataset_name = os.path.basename(input).split('.')[0] 3993 res = ['import %s as %s'%(input, dataset_name)] 3994 if not type is None: 3995 res.append('set %s.type = %s'%(dataset_name, type)) 3996 return res
3997 3998 fifo_status = {'warned_fifo':False,'fifo_used_up':False} 3999 def warn_fifo(input): 4000 if not input.endswith('.fifo'): 4001 return False 4002 if not fifo_status['fifo_used_up']: 4003 fifo_status['fifo_used_up'] = True 4004 return False 4005 else: 4006 if not fifo_status['warned_fifo']: 4007 logger.warning('Only the first MA5 analysis/reconstructions can be run on a fifo. Subsequent runs will skip fifo inputs.') 4008 fifo_status['warned_fifo'] = True 4009 return True
4010 4011 # Then the event file(s) input(s) 4012 inputs_load = [] 4013 for input in inputs: 4014 inputs_load.extend(get_import(input)) 4015 4016 submit_command = 'submit %s'%submit_folder+'_%s' 4017 4018 # Keep track of the reconstruction outpus in the MA5 workflow 4019 # Keys are reconstruction names and values are .lhe.gz reco file paths. 4020 # We put by default already the lhco/root ones present 4021 reconstruction_outputs = { 4022 'lhco_input':[f for f in inputs if 4023 f.endswith('.lhco') or f.endswith('.lhco.gz')], 4024 'root_input':[f for f in inputs if 4025 f.endswith('.root') or f.endswith('.root.gz')]} 4026 4027 # If a recasting card has to be written out, chose here its path 4028 recasting_card_path = pjoin(run_dir_path, 4029 '_'.join([run_tag,os.path.basename(submit_folder),'recasting_card.dat'])) 4030 4031 # Make sure to only run over one analysis over each fifo. 4032 for definition_type, name in self['order']: 4033 if definition_type == 'reconstruction': 4034 analysis_cmds = list(self['reconstruction'][name]['commands']) 4035 reco_outputs = [] 4036 for i_input, input in enumerate(inputs): 4037 # Skip lhco/root as they must not be reconstructed 4038 if not MadAnalysis5Card.events_can_be_reconstructed(input): 4039 continue 4040 # Make sure the input is not a used up fifo. 4041 if warn_fifo(input): 4042 continue 4043 analysis_cmds.append('import %s as reco_events'%input) 4044 if self['reconstruction'][name]['reco_output']=='lhe': 4045 reco_outputs.append('%s_%s.lhe.gz'%(os.path.basename( 4046 input).replace('_events','').split('.')[0],name)) 4047 analysis_cmds.append('set main.outputfile=%s'%reco_outputs[-1]) 4048 elif self['reconstruction'][name]['reco_output']=='root': 4049 reco_outputs.append('%s_%s.root'%(os.path.basename( 4050 input).replace('_events','').split('.')[0],name)) 4051 analysis_cmds.append('set main.fastsim.rootfile=%s'%reco_outputs[-1]) 4052 analysis_cmds.append( 4053 submit_command%('reco_%s_%d'%(name,i_input+1))) 4054 analysis_cmds.append('remove reco_events') 4055 4056 reconstruction_outputs[name]= [pjoin(run_dir_path,rec_out) 4057 for rec_out in reco_outputs] 4058 if len(reco_outputs)>0: 4059 cmds_list.append(('_reco_%s'%name,analysis_cmds)) 4060 4061 elif definition_type == 'analyses': 4062 if self['mode']=='parton': 4063 cmds_list.append( (name, UFO_load+inputs_load+ 4064 self['analyses'][name]['commands']+[submit_command%name]) ) 4065 elif self['mode']=='hadron': 4066 # Also run on the already reconstructed root/lhco files if found. 4067 for reco in self['analyses'][name]['reconstructions']+\ 4068 ['lhco_input','root_input']: 4069 if len(reconstruction_outputs[reco])==0: 4070 continue 4071 if self['reconstruction'][reco]['reco_output']=='lhe': 4072 # For the reconstructed lhe output we must be in parton mode 4073 analysis_cmds = ['set main.mode = parton'] 4074 else: 4075 analysis_cmds = [] 4076 analysis_cmds.extend(sum([get_import(rec_out) for 4077 rec_out in reconstruction_outputs[reco]],[])) 4078 analysis_cmds.extend(self['analyses'][name]['commands']) 4079 analysis_cmds.append(submit_command%('%s_%s'%(name,reco))) 4080 cmds_list.append( ('%s_%s'%(name,reco),analysis_cmds) ) 4081 4082 elif definition_type == 'recasting': 4083 if len(self['recasting']['card'])==0: 4084 continue 4085 if name == 'card': 4086 # Create the card here 4087 open(recasting_card_path,'w').write('\n'.join(self['recasting']['card'])) 4088 if name == 'commands': 4089 recasting_cmds = list(self['recasting']['commands']) 4090 # Exclude LHCO files here of course 4091 n_inputs = 0 4092 for input in inputs: 4093 if not MadAnalysis5Card.events_can_be_reconstructed(input): 4094 continue 4095 # Make sure the input is not a used up fifo. 4096 if warn_fifo(input): 4097 continue 4098 recasting_cmds.extend(get_import(input,'signal')) 4099 n_inputs += 1 4100 4101 recasting_cmds.append('set main.recast.card_path=%s'%recasting_card_path) 4102 recasting_cmds.append(submit_command%'Recasting') 4103 if n_inputs>0: 4104 cmds_list.append( ('Recasting',recasting_cmds)) 4105 4106 return cmds_list 4107
4108 -class RunCardNLO(RunCard):
4109 """A class object for the run_card for a (aMC@)NLO pocess""" 4110 4111 LO = False 4112
4113 - def default_setup(self):
4114 """define the default value""" 4115 4116 self.add_param('run_tag', 'tag_1', include=False) 4117 self.add_param('nevents', 10000) 4118 self.add_param('req_acc', -1.0, include=False) 4119 self.add_param('nevt_job', -1, include=False) 4120 self.add_param('event_norm', 'average') 4121 #FO parameter 4122 self.add_param('req_acc_fo', 0.01, include=False) 4123 self.add_param('npoints_fo_grid', 5000, include=False) 4124 self.add_param('niters_fo_grid', 4, include=False) 4125 self.add_param('npoints_fo', 10000, include=False) 4126 self.add_param('niters_fo', 6, include=False) 4127 #seed and collider 4128 self.add_param('iseed', 0) 4129 self.add_param('lpp1', 1, fortran_name='lpp(1)') 4130 self.add_param('lpp2', 1, fortran_name='lpp(2)') 4131 self.add_param('ebeam1', 6500.0, fortran_name='ebeam(1)') 4132 self.add_param('ebeam2', 6500.0, fortran_name='ebeam(2)') 4133 self.add_param('pdlabel', 'nn23nlo', allowed=['lhapdf', 'cteq6_m','cteq6_d','cteq6_l','cteq6l1', 'nn23lo','nn23lo1','nn23nlo','ct14q00','ct14q07','ct14q14','ct14q21']) 4134 self.add_param('lhaid', [244600],fortran_name='lhaPDFid') 4135 self.add_param('lhapdfsetname', ['internal_use_only'], system=True) 4136 #shower and scale 4137 self.add_param('parton_shower', 'HERWIG6', fortran_name='shower_mc') 4138 self.add_param('shower_scale_factor',1.0) 4139 self.add_param('fixed_ren_scale', False) 4140 self.add_param('fixed_fac_scale', False) 4141 self.add_param('mur_ref_fixed', 91.118) 4142 self.add_param('muf1_ref_fixed', -1.0, hidden=True) 4143 self.add_param('muf_ref_fixed', 91.118) 4144 self.add_param('muf2_ref_fixed', -1.0, hidden=True) 4145 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") 4146 self.add_param('fixed_qes_scale', False, hidden=True) 4147 self.add_param('qes_ref_fixed', -1.0, hidden=True) 4148 self.add_param('mur_over_ref', 1.0) 4149 self.add_param('muf_over_ref', 1.0) 4150 self.add_param('muf1_over_ref', -1.0, hidden=True) 4151 self.add_param('muf2_over_ref', -1.0, hidden=True) 4152 self.add_param('qes_over_ref', -1.0, hidden=True) 4153 self.add_param('reweight_scale', [True], fortran_name='lscalevar') 4154 self.add_param('rw_rscale_down', -1.0, hidden=True) 4155 self.add_param('rw_rscale_up', -1.0, hidden=True) 4156 self.add_param('rw_fscale_down', -1.0, hidden=True) 4157 self.add_param('rw_fscale_up', -1.0, hidden=True) 4158 self.add_param('rw_rscale', [1.0,2.0,0.5], fortran_name='scalevarR') 4159 self.add_param('rw_fscale', [1.0,2.0,0.5], fortran_name='scalevarF') 4160 self.add_param('reweight_pdf', [False], fortran_name='lpdfvar') 4161 self.add_param('pdf_set_min', 244601, hidden=True) 4162 self.add_param('pdf_set_max', 244700, hidden=True) 4163 self.add_param('store_rwgt_info', False) 4164 self.add_param('systematics_program', 'none', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics') 4165 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.') 4166 4167 #merging 4168 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]") 4169 self.add_param('bwcutoff', 15.0) 4170 #cuts 4171 self.add_param('jetalgo', 1.0) 4172 self.add_param('jetradius', 0.7) 4173 self.add_param('ptj', 10.0 , cut=True) 4174 self.add_param('etaj', -1.0, cut=True) 4175 self.add_param('gamma_is_j', True) 4176 self.add_param('ptl', 0.0, cut=True) 4177 self.add_param('etal', -1.0, cut=True) 4178 self.add_param('drll', 0.0, cut=True) 4179 self.add_param('drll_sf', 0.0, cut=True) 4180 self.add_param('mll', 0.0, cut=True) 4181 self.add_param('mll_sf', 30.0, cut=True) 4182 self.add_param('rphreco', 0.1) 4183 self.add_param('etaphreco', -1.0) 4184 self.add_param('lepphreco', True) 4185 self.add_param('quarkphreco', True) 4186 self.add_param('ptgmin', 20.0, cut=True) 4187 self.add_param('etagamma', -1.0) 4188 self.add_param('r0gamma', 0.4) 4189 self.add_param('xn', 1.0) 4190 self.add_param('epsgamma', 1.0) 4191 self.add_param('isoem', True) 4192 self.add_param('maxjetflavor', 4, hidden=True) 4193 self.add_param('pineappl', False) 4194 self.add_param('lhe_version', 3, hidden=True, include=False) 4195 4196 #internal variable related to FO_analyse_card 4197 self.add_param('FO_LHE_weight_ratio',1e-3, hidden=True, system=True) 4198 self.add_param('FO_LHE_postprocessing',['grouping','random'], 4199 hidden=True, system=True, include=False) 4200 4201 # parameter allowing to define simple cut via the pdg 4202 self.add_param('pt_min_pdg',{'__type__':0.}, include=False,cut=True) 4203 self.add_param('pt_max_pdg',{'__type__':0.}, include=False,cut=True) 4204 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True) 4205 self.add_param('mxx_only_part_antipart', {'default':False}, include=False, hidden=True) 4206 4207 #hidden parameter that are transfer to the fortran code 4208 self.add_param('pdg_cut',[0], hidden=True, system=True) # store which PDG are tracked 4209 self.add_param('ptmin4pdg',[0.], hidden=True, system=True) # store pt min 4210 self.add_param('ptmax4pdg',[-1.], hidden=True, system=True) 4211 self.add_param('mxxmin4pdg',[0.], hidden=True, system=True) 4212 self.add_param('mxxpart_antipart', [False], hidden=True, system=True)
4213
4214 - def check_validity(self):
4215 """check the validity of the various input""" 4216 4217 super(RunCardNLO, self).check_validity() 4218 4219 # for lepton-lepton collisions, ignore 'pdlabel' and 'lhaid' 4220 if abs(self['lpp1'])!=1 or abs(self['lpp2'])!=1: 4221 if self['lpp1'] == 1 or self['lpp2']==1: 4222 raise InvalidRunCard('Process like Deep Inelastic scattering not supported at NLO accuracy.') 4223 4224 if self['pdlabel']!='nn23nlo' or self['reweight_pdf']: 4225 self['pdlabel']='nn23nlo' 4226 self['reweight_pdf']=[False] 4227 logger.info('''Lepton-lepton collisions: ignoring PDF related parameters in the run_card.dat (pdlabel, lhaid, reweight_pdf, ...)''') 4228 4229 # For FxFx merging, make sure that the following parameters are set correctly: 4230 if self['ickkw'] == 3: 4231 # 1. Renormalization and factorization (and ellis-sexton scales) are not fixed 4232 scales=['fixed_ren_scale','fixed_fac_scale','fixed_QES_scale'] 4233 for scale in scales: 4234 if self[scale]: 4235 logger.warning('''For consistency in the FxFx merging, \'%s\' has been set to false''' 4236 % scale,'$MG:BOLD') 4237 self[scale]= False 4238 #and left to default dynamical scale 4239 if len(self["dynamical_scale_choice"]) > 1 or self["dynamical_scale_choice"][0] != -1: 4240 self["dynamical_scale_choice"] = [-1] 4241 self["reweight_scale"]=[self["reweight_scale"][0]] 4242 logger.warning('''For consistency in the FxFx merging, dynamical_scale_choice has been set to -1 (default)''' 4243 ,'$MG:BOLD') 4244 4245 # 2. Use kT algorithm for jets with pseudo-code size R=1.0 4246 jetparams=['jetradius','jetalgo'] 4247 for jetparam in jetparams: 4248 if float(self[jetparam]) != 1.0: 4249 logger.info('''For consistency in the FxFx merging, \'%s\' has been set to 1.0''' 4250 % jetparam ,'$MG:BOLD') 4251 self[jetparam] = 1.0 4252 elif self['ickkw'] == -1 and (self["dynamical_scale_choice"][0] != -1 or 4253 len(self["dynamical_scale_choice"]) > 1): 4254 self["dynamical_scale_choice"] = [-1] 4255 self["reweight_scale"]=[self["reweight_scale"][0]] 4256 logger.warning('''For consistency with the jet veto, the scale which will be used is ptj. dynamical_scale_choice will be set at -1.''' 4257 ,'$MG:BOLD') 4258 4259 # For interface to PINEAPPL, need to use LHAPDF and reweighting to get scale uncertainties 4260 if self['pineappl'] and self['pdlabel'].lower() != 'lhapdf': 4261 raise InvalidRunCard('PineAPPL generation only possible with the use of LHAPDF') 4262 if self['pineappl'] and not self['reweight_scale']: 4263 raise InvalidRunCard('PineAPPL generation only possible with including' +\ 4264 ' the reweighting to get scale dependence') 4265 4266 # Hidden values check 4267 if self['qes_ref_fixed'] == -1.0: 4268 self['qes_ref_fixed']=self['mur_ref_fixed'] 4269 if self['qes_over_ref'] == -1.0: 4270 self['qes_over_ref']=self['mur_over_ref'] 4271 if self['muf1_over_ref'] != -1.0 and self['muf1_over_ref'] == self['muf2_over_ref']: 4272 self['muf_over_ref']=self['muf1_over_ref'] 4273 if self['muf1_over_ref'] == -1.0: 4274 self['muf1_over_ref']=self['muf_over_ref'] 4275 if self['muf2_over_ref'] == -1.0: 4276 self['muf2_over_ref']=self['muf_over_ref'] 4277 if self['muf1_ref_fixed'] != -1.0 and self['muf1_ref_fixed'] == self['muf2_ref_fixed']: 4278 self['muf_ref_fixed']=self['muf1_ref_fixed'] 4279 if self['muf1_ref_fixed'] == -1.0: 4280 self['muf1_ref_fixed']=self['muf_ref_fixed'] 4281 if self['muf2_ref_fixed'] == -1.0: 4282 self['muf2_ref_fixed']=self['muf_ref_fixed'] 4283 # overwrite rw_rscale and rw_fscale when rw_(r/f)scale_(down/up) are explicitly given in the run_card for backward compatibility. 4284 if (self['rw_rscale_down'] != -1.0 and ['rw_rscale_down'] not in self['rw_rscale']) or\ 4285 (self['rw_rscale_up'] != -1.0 and ['rw_rscale_up'] not in self['rw_rscale']): 4286 self['rw_rscale']=[1.0,self['rw_rscale_up'],self['rw_rscale_down']] 4287 if (self['rw_fscale_down'] != -1.0 and ['rw_fscale_down'] not in self['rw_fscale']) or\ 4288 (self['rw_fscale_up'] != -1.0 and ['rw_fscale_up'] not in self['rw_fscale']): 4289 self['rw_fscale']=[1.0,self['rw_fscale_up'],self['rw_fscale_down']] 4290 4291 # PDF reweighting check 4292 if any(self['reweight_pdf']): 4293 # check that we use lhapdf if reweighting is ON 4294 if self['pdlabel'] != "lhapdf": 4295 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.') 4296 4297 # make sure set have reweight_pdf and lhaid of length 1 when not including lhapdf 4298 if self['pdlabel'] != "lhapdf": 4299 self['reweight_pdf']=[self['reweight_pdf'][0]] 4300 self['lhaid']=[self['lhaid'][0]] 4301 4302 # make sure set have reweight_scale and dyn_scale_choice of length 1 when fixed scales: 4303 if self['fixed_ren_scale'] and self['fixed_fac_scale']: 4304 self['reweight_scale']=[self['reweight_scale'][0]] 4305 self['dynamical_scale_choice']=[0] 4306 4307 # If there is only one reweight_pdf/reweight_scale, but 4308 # lhaid/dynamical_scale_choice are longer, expand the 4309 # reweight_pdf/reweight_scale list to have the same length 4310 if len(self['reweight_pdf']) == 1 and len(self['lhaid']) != 1: 4311 self['reweight_pdf']=self['reweight_pdf']*len(self['lhaid']) 4312 logger.warning("Setting 'reweight_pdf' for all 'lhaid' to %s" % self['reweight_pdf'][0]) 4313 if len(self['reweight_scale']) == 1 and len(self['dynamical_scale_choice']) != 1: 4314 self['reweight_scale']=self['reweight_scale']*len(self['dynamical_scale_choice']) 4315 logger.warning("Setting 'reweight_scale' for all 'dynamical_scale_choice' to %s" % self['reweight_pdf'][0]) 4316 4317 # Check that there are no identical elements in lhaid or dynamical_scale_choice 4318 if len(self['lhaid']) != len(set(self['lhaid'])): 4319 raise InvalidRunCard("'lhaid' has two or more identical entries. They have to be all different for the code to work correctly.") 4320 if len(self['dynamical_scale_choice']) != len(set(self['dynamical_scale_choice'])): 4321 raise InvalidRunCard("'dynamical_scale_choice' has two or more identical entries. They have to be all different for the code to work correctly.") 4322 4323 # Check that lenght of lists are consistent 4324 if len(self['reweight_pdf']) != len(self['lhaid']): 4325 raise InvalidRunCard("'reweight_pdf' and 'lhaid' lists should have the same length") 4326 if len(self['reweight_scale']) != len(self['dynamical_scale_choice']): 4327 raise InvalidRunCard("'reweight_scale' and 'dynamical_scale_choice' lists should have the same length") 4328 if len(self['dynamical_scale_choice']) > 10 : 4329 raise InvalidRunCard("Length of list for 'dynamical_scale_choice' too long: max is 10.") 4330 if len(self['lhaid']) > 25 : 4331 raise InvalidRunCard("Length of list for 'lhaid' too long: max is 25.") 4332 if len(self['rw_rscale']) > 9 : 4333 raise InvalidRunCard("Length of list for 'rw_rscale' too long: max is 9.") 4334 if len(self['rw_fscale']) > 9 : 4335 raise InvalidRunCard("Length of list for 'rw_fscale' too long: max is 9.") 4336 # make sure that the first element of rw_rscale and rw_fscale is the 1.0 4337 if 1.0 not in self['rw_rscale']: 4338 logger.warning("'1.0' has to be part of 'rw_rscale', adding it") 4339 self['rw_rscale'].insert(0,1.0) 4340 if 1.0 not in self['rw_fscale']: 4341 logger.warning("'1.0' has to be part of 'rw_fscale', adding it") 4342 self['rw_fscale'].insert(0,1.0) 4343 if self['rw_rscale'][0] != 1.0 and 1.0 in self['rw_rscale']: 4344 a=self['rw_rscale'].index(1.0) 4345 self['rw_rscale'][0],self['rw_rscale'][a]=self['rw_rscale'][a],self['rw_rscale'][0] 4346 if self['rw_fscale'][0] != 1.0 and 1.0 in self['rw_fscale']: 4347 a=self['rw_fscale'].index(1.0) 4348 self['rw_fscale'][0],self['rw_fscale'][a]=self['rw_fscale'][a],self['rw_fscale'][0] 4349 # check that all elements of rw_rscale and rw_fscale are diffent. 4350 if len(self['rw_rscale']) != len(set(self['rw_rscale'])): 4351 raise InvalidRunCard("'rw_rscale' has two or more identical entries. They have to be all different for the code to work correctly.") 4352 if len(self['rw_fscale']) != len(set(self['rw_fscale'])): 4353 raise InvalidRunCard("'rw_fscale' has two or more identical entries. They have to be all different for the code to work correctly.") 4354 4355 4356 # check that ebeam is bigger than the proton mass. 4357 for i in [1,2]: 4358 if self['lpp%s' % i ] not in [1,2]: 4359 continue 4360 4361 if self['ebeam%i' % i] < 0.938: 4362 if self['ebeam%i' %i] == 0: 4363 logger.warning("At rest proton mode set: Energy beam set to 0.938") 4364 self.set('ebeam%i' %i, 0.938) 4365 else: 4366 raise InvalidRunCard("Energy for beam %i lower than proton mass. Please fix this")
4367 4368
4370 4371 # set the pdg_for_cut fortran parameter 4372 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys())+ 4373 list(self['mxx_min_pdg'].keys())+ list(self['mxx_only_part_antipart'].keys())) 4374 pdg_to_cut.discard('__type__') 4375 pdg_to_cut.discard('default') 4376 if len(pdg_to_cut)>25: 4377 raise Exception("Maximum 25 different PDGs are allowed for PDG specific cut") 4378 4379 if any(int(pdg)<0 for pdg in pdg_to_cut): 4380 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes') 4381 raise MadGraph5Error('Some PDG specific cuts are defined with negative PDG codes') 4382 4383 4384 if any(pdg in pdg_to_cut for pdg in [21,22,11,13,15]+ list(range(self['maxjetflavor']+1))): 4385 # Note that this will double check in the fortran code 4386 raise Exception("Can not use PDG related cuts for massless SM particles/leptons") 4387 if pdg_to_cut: 4388 self['pdg_cut'] = list(pdg_to_cut) 4389 self['ptmin4pdg'] = [] 4390 self['ptmax4pdg'] = [] 4391 self['mxxmin4pdg'] = [] 4392 self['mxxpart_antipart'] = [] 4393 for pdg in self['pdg_cut']: 4394 for var in ['pt','mxx']: 4395 for minmax in ['min', 'max']: 4396 if var == 'mxx' and minmax == 'max': 4397 continue 4398 new_var = '%s%s4pdg' % (var, minmax) 4399 old_var = '%s_%s_pdg' % (var, minmax) 4400 default = 0. if minmax=='min' else -1. 4401 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default) 4402 #special for mxx_part_antipart 4403 old_var = 'mxx_only_part_antipart' 4404 new_var = 'mxxpart_antipart' 4405 if 'default' in self[old_var]: 4406 default = self[old_var]['default'] 4407 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default) 4408 else: 4409 if str(pdg) not in self[old_var]: 4410 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg)) 4411 self[new_var].append(self[old_var][str(pdg)]) 4412 else: 4413 self['pdg_cut'] = [0] 4414 self['ptmin4pdg'] = [0.] 4415 self['ptmax4pdg'] = [-1.] 4416 self['mxxmin4pdg'] = [0.] 4417 self['mxxpart_antipart'] = [False]
4418
4419 - def write(self, output_file, template=None, python_template=False, **opt):
4420 """Write the run_card in output_file according to template 4421 (a path to a valid run_card)""" 4422 4423 if not template: 4424 if not MADEVENT: 4425 template = pjoin(MG5DIR, 'Template', 'NLO', 'Cards', 4426 'run_card.dat') 4427 python_template = True 4428 else: 4429 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat') 4430 python_template = False 4431 4432 super(RunCardNLO, self).write(output_file, template=template, 4433 python_template=python_template, **opt)
4434 4435
4436 - def create_default_for_process(self, proc_characteristic, history, proc_def):
4437 """Rules 4438 e+ e- beam -> lpp:0 ebeam:500 4439 p p beam -> set maxjetflavor automatically 4440 """ 4441 4442 # check for beam_id 4443 beam_id = set() 4444 for proc in proc_def: 4445 for leg in proc['legs']: 4446 if not leg['state']: 4447 beam_id.add(leg['id']) 4448 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]): 4449 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7]) 4450 self['maxjetflavor'] = maxjetflavor 4451 pass 4452 elif any(id in beam_id for id in [11,-11,13,-13]): 4453 self['lpp1'] = 0 4454 self['lpp2'] = 0 4455 self['ebeam1'] = 500 4456 self['ebeam2'] = 500 4457 else: 4458 self['lpp1'] = 0 4459 self['lpp2'] = 0 4460 4461 if proc_characteristic['ninitial'] == 1: 4462 #remove all cut 4463 self.remove_all_cut() 4464 4465 # Check if need matching 4466 min_particle = 99 4467 max_particle = 0 4468 for proc in proc_def: 4469 min_particle = min(len(proc['legs']), min_particle) 4470 max_particle = max(len(proc['legs']), max_particle) 4471 matching = False 4472 if min_particle != max_particle: 4473 #take one of the process with min_particle 4474 for procmin in proc_def: 4475 if len(procmin['legs']) != min_particle: 4476 continue 4477 else: 4478 idsmin = [l['id'] for l in procmin['legs']] 4479 break 4480 4481 for procmax in proc_def: 4482 if len(procmax['legs']) != max_particle: 4483 continue 4484 idsmax = [l['id'] for l in procmax['legs']] 4485 for i in idsmin: 4486 if i not in idsmax: 4487 continue 4488 else: 4489 idsmax.remove(i) 4490 for j in idsmax: 4491 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]: 4492 break 4493 else: 4494 # all are jet => matching is ON 4495 matching=True 4496 break 4497 4498 if matching: 4499 self['ickkw'] = 3 4500 self['fixed_ren_scale'] = False 4501 self["fixed_fac_scale"] = False 4502 self["fixed_QES_scale"] = False 4503 self["jetalgo"] = 1 4504 self["jetradius"] = 1 4505 self["parton_shower"] = "PYTHIA8"
4506
4507 4508 4509 4510 -class MadLoopParam(ConfigFile):
4511 """ a class for storing/dealing with the file MadLoopParam.dat 4512 contains a parser to read it, facilities to write a new file,... 4513 """ 4514 4515 _ID_reduction_tool_map = {1:'CutTools', 4516 2:'PJFry++', 4517 3:'IREGI', 4518 4:'Golem95', 4519 5:'Samurai', 4520 6:'Ninja', 4521 7:'COLLIER'} 4522
4523 - def default_setup(self):
4524 """initialize the directory to the default value""" 4525 4526 self.add_param("MLReductionLib", "6|7|1") 4527 self.add_param("IREGIMODE", 2) 4528 self.add_param("IREGIRECY", True) 4529 self.add_param("CTModeRun", -1) 4530 self.add_param("MLStabThres", 1e-3) 4531 self.add_param("NRotations_DP", 0) 4532 self.add_param("NRotations_QP", 0) 4533 self.add_param("ImprovePSPoint", 2) 4534 self.add_param("CTLoopLibrary", 2) 4535 self.add_param("CTStabThres", 1e-2) 4536 self.add_param("CTModeInit", 1) 4537 self.add_param("CheckCycle", 3) 4538 self.add_param("MaxAttempts", 10) 4539 self.add_param("ZeroThres", 1e-9) 4540 self.add_param("OSThres", 1.0e-8) 4541 self.add_param("DoubleCheckHelicityFilter", True) 4542 self.add_param("WriteOutFilters", True) 4543 self.add_param("UseLoopFilter", False) 4544 self.add_param("HelicityFilterLevel", 2) 4545 self.add_param("LoopInitStartOver", False) 4546 self.add_param("HelInitStartOver", False) 4547 self.add_param("UseQPIntegrandForNinja", True) 4548 self.add_param("UseQPIntegrandForCutTools", True) 4549 self.add_param("COLLIERMode", 1) 4550 self.add_param("COLLIERComputeUVpoles", True) 4551 self.add_param("COLLIERComputeIRpoles", True) 4552 self.add_param("COLLIERRequiredAccuracy", 1.0e-8) 4553 self.add_param("COLLIERCanOutput",False) 4554 self.add_param("COLLIERGlobalCache",-1) 4555 self.add_param("COLLIERUseCacheForPoles",False) 4556 self.add_param("COLLIERUseInternalStabilityTest",True)
4557
4558 - def read(self, finput):
4559 """Read the input file, this can be a path to a file, 4560 a file object, a str with the content of the file.""" 4561 4562 if isinstance(finput, str): 4563 if "\n" in finput: 4564 finput = finput.split('\n') 4565 elif os.path.isfile(finput): 4566 finput = open(finput) 4567 else: 4568 raise Exception("No such file %s" % input) 4569 4570 previous_line= '' 4571 for line in finput: 4572 if previous_line.startswith('#'): 4573 name = previous_line[1:].split()[0] 4574 value = line.strip() 4575 if len(value) and value[0] not in ['#', '!']: 4576 self.__setitem__(name, value, change_userdefine=True) 4577 previous_line = line
4578 4579
4580 - def write(self, outputpath, template=None,commentdefault=False):
4581 4582 if not template: 4583 if not MADEVENT: 4584 template = pjoin(MG5DIR, 'Template', 'loop_material', 'StandAlone', 4585 'Cards', 'MadLoopParams.dat') 4586 else: 4587 template = pjoin(MEDIR, 'Cards', 'MadLoopParams_default.dat') 4588 fsock = open(template, 'r') 4589 template = fsock.readlines() 4590 fsock.close() 4591 4592 if isinstance(outputpath, str): 4593 output = open(outputpath, 'w') 4594 else: 4595 output = outputpath 4596 4597 def f77format(value): 4598 if isinstance(value, bool): 4599 if value: 4600 return '.true.' 4601 else: 4602 return '.false.' 4603 elif isinstance(value, int): 4604 return value 4605 elif isinstance(value, float): 4606 tmp ='%e' % value 4607 return tmp.replace('e','d') 4608 elif isinstance(value, str): 4609 return value 4610 else: 4611 raise Exception("Can not format input %s" % type(value))
4612 4613 name = '' 4614 done = set() 4615 for line in template: 4616 if name: 4617 done.add(name) 4618 if commentdefault and name.lower() not in self.user_set : 4619 output.write('!%s\n' % f77format(self[name])) 4620 else: 4621 output.write('%s\n' % f77format(self[name])) 4622 name='' 4623 continue 4624 elif line.startswith('#'): 4625 name = line[1:].split()[0] 4626 output.write(line)
4627