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