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