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