1
2
3
4
5
6
7
8
9
10
11
12
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')
64
67 """ """
68
69 ordered_items = ['mgversion', 'mg5proccard', 'mgproccard', 'mgruncard',
70 'slha','initrwgt','mggenerationinfo', 'mgpythiacard', 'mgpgscard',
71 'mgdelphescard', 'mgdelphestrigger','mgshowercard',
72 'ma5card_parton','ma5card_hadron','run_settings']
73
74 capitalized_items = {
75 'mgversion': 'MGVersion',
76 'mg5proccard': 'MG5ProcCard',
77 'mgproccard': 'MGProcCard',
78 'mgruncard': 'MGRunCard',
79 'ma5card_parton' : 'MA5Card_parton',
80 'ma5card_hadron' : 'MA5Card_hadron',
81 'mggenerationinfo': 'MGGenerationInfo',
82 'mgpythiacard': 'MGPythiaCard',
83 'mgpgscard': 'MGPGSCard',
84 'mgdelphescard': 'MGDelphesCard',
85 'mgdelphestrigger': 'MGDelphesTrigger',
86 'mgshowercard': 'MGShowerCard' }
87
88 forbid_cdata = ['initrwgt']
89
91 """ """
92
93 if isinstance(banner_path, Banner):
94 dict.__init__(self, banner_path)
95 self.lhe_version = banner_path.lhe_version
96 return
97 else:
98 dict.__init__(self)
99
100
101 if MADEVENT:
102 self['mgversion'] = '#%s\n' % open(pjoin(MEDIR, 'MGMEVersion.txt')).read()
103 else:
104 info = misc.get_pkg_info()
105 self['mgversion'] = info['version']+'\n'
106
107 self.lhe_version = None
108
109
110 if banner_path:
111 self.read_banner(banner_path)
112
113
114
115
116 pat_begin=re.compile('<(?P<name>\w*)>')
117 pat_end=re.compile('</(?P<name>\w*)>')
118
119 tag_to_file={'slha':'param_card.dat',
120 'mgruncard':'run_card.dat',
121 'mgpythiacard':'pythia_card.dat',
122 'mgpgscard' : 'pgs_card.dat',
123 'mgdelphescard':'delphes_card.dat',
124 'mgdelphestrigger':'delphes_trigger.dat',
125 'mg5proccard':'proc_card_mg5.dat',
126 'mgproccard': 'proc_card.dat',
127 'init': '',
128 'mggenerationinfo':'',
129 'scalesfunctionalform':'',
130 'montecarlomasses':'',
131 'initrwgt':'',
132 'madspin':'madspin_card.dat',
133 'mgshowercard':'shower_card.dat',
134 'pythia8':'pythia8_card.dat',
135 'ma5card_parton':'madanalysis5_parton_card.dat',
136 'ma5card_hadron':'madanalysis5_hadron_card.dat',
137 'run_settings':''
138 }
139
141 """read a banner"""
142
143 if isinstance(input_path, str):
144 if input_path.find('\n') ==-1:
145 input_path = open(input_path)
146 else:
147 def split_iter(string):
148 return (x.groups(0)[0] for x in re.finditer(r"([^\n]*\n)", string, re.DOTALL))
149 input_path = split_iter(input_path)
150
151 text = ''
152 store = False
153 for line in input_path:
154 if self.pat_begin.search(line):
155 if self.pat_begin.search(line).group('name').lower() in self.tag_to_file:
156 tag = self.pat_begin.search(line).group('name').lower()
157 store = True
158 continue
159 if store and self.pat_end.search(line):
160 if tag == self.pat_end.search(line).group('name').lower():
161 self[tag] = text
162 text = ''
163 store = False
164 if store and not line.startswith(('<![CDATA[',']]>')):
165 if line.endswith('\n'):
166 text += line
167 else:
168 text += '%s%s' % (line, '\n')
169
170
171 if "</init>" in line:
172 break
173 elif "<event>" in line:
174 break
175
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
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
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
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
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
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
262 """Change the seed value in the banner"""
263
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
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
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
299
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
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
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
346 """modify the init information with the associate cross-section"""
347 assert isinstance(cross, dict)
348
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
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
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
561
562
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
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()
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
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):
700
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
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
767
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
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):
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
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
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
844 cmd = cmds[0]
845
846 if cmd == 'output':
847
848 self.clean(allow_for_removal = ['output'], keep_switch=True,
849 remove_bef_last='output')
850 elif cmd == 'generate':
851
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
868 elif cmds[1] == 'proc_v4':
869
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
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
901 while nline > -len(self):
902 switch = False
903
904
905 if not removal and remove_bef_last:
906 if self[nline].startswith(remove_bef_last):
907 removal = True
908 switch = True
909
910
911 if switch and keep_switch:
912 nline -= 1
913 continue
914
915
916 if any([self[nline].startswith(arg) for arg in to_remove]):
917 self.pop(nline)
918 continue
919
920
921 if removal:
922 if allow_for_removal:
923
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
930 self.pop(nline)
931 continue
932
933
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
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
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
967
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
987 self.user_set = set()
988 self.auto_set = set()
989 self.system_only = set()
990 self.lower_to_case = {}
991 self.list_parameter = {}
992 self.dict_parameter = {}
993 self.comments = {}
994
995 self.allowed_value = {}
996
997 self.default_setup()
998
999
1000
1001 if isinstance(finput, (file, str, StringIO.StringIO)):
1002 self.read(finput, **opt)
1003
1006
1008 return self.__class__(self)
1009
1011 """define the sum"""
1012 assert isinstance(other, dict)
1013 base = self.__class__(self)
1014
1015 base.update((key.lower(),value) for key, value in other.items())
1016
1017 return base
1018
1020 """define the sum"""
1021 new = copy.copy(other)
1022 new.update((key, value) for key, value in self.items())
1023 return new
1024
1027
1032
1033
1034
1035
1036
1037
1040
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
1077 self.__init__()
1078
1079 name = name.strip()
1080 lower_name = name.lower()
1081
1082
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
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
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
1102 if lower_name in self.list_parameter:
1103 targettype = self.list_parameter[lower_name]
1104
1105
1106
1107 if isinstance(value, str):
1108
1109 value = value.strip()
1110 if value.startswith('[') and value.endswith(']'):
1111 value = value[1:-1]
1112
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
1136 values =[self.format_variable(v, targettype, name=name)
1137 for v in value]
1138
1139
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
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
1175 dict.__setitem__(self, lower_name, values)
1176 if change_userdefine:
1177 self.user_set.add(lower_name)
1178
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
1183
1184 if isinstance(value, str):
1185 value = value.strip()
1186
1187
1188
1189
1190
1191
1192
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
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
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
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
1310
1311
1312
1313 if system:
1314 self.system_only.add(lower_name)
1315 if comment:
1316 self.comments[lower_name] = comment
1317
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
1448
1449
1450
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
1474 if not changeifuserset:
1475 if name.lower() in self.user_set:
1476
1477 return
1478
1479 self.__setitem__(name, value, change_userdefine=user, raiseerror=raiseerror)
1480
1484 """A class to handle information which are passed from MadGraph to the madevent
1485 interface."""
1486
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
1546 """an object for the GridpackCard"""
1547
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
1611 """ Implements the Pythia8 card."""
1612
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
1632 """ Sets up the list of available PY8 parameters."""
1633
1634
1635
1636 self.add_param("Main:numberOfEvents", -1)
1637
1638
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
1642 self.add_param("JetMatching:nJetMax", -1, always_write_to_card=False)
1643
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
1647 self.add_param("Merging:nJetMax", -1, always_write_to_card=False)
1648
1649
1650 self.add_param("SysCalc:fullCutVariation", False)
1651
1652
1653
1654 self.add_param("HEPMCoutput:file", 'auto')
1655
1656
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
1668
1669 self.add_param("JetMatching:etaJetMax", 1000.0, hidden=True, always_write_to_card=True)
1670
1671
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
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
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
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
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
1738
1739 self.add_default_subruns('parameters')
1740
1742
1743
1744
1745 self.hidden_param = []
1746 self.hidden_params_to_always_write = set()
1747 self.visible_params_to_always_write = set()
1748
1749 self.params_to_never_write = set()
1750
1751
1752
1753 self.system_set = set()
1754
1755
1756
1757 self.add_default_subruns('attributes')
1758
1759
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
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
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
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
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
1835
1836 @staticmethod
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
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
1905 visible_param = [p for p in visible_param if p.lower() not in self.params_to_never_write]
1906
1907
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
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
1925
1926 subruns_to_write = {}
1927
1928
1929
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
1941 if 'Main:subrun' in res:
1942 res.insert(0,res.pop(res.index('Main:subrun')))
1943
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
1952
1953 output = StringIO.StringIO()
1954
1955
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
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
1973 last_pos = tmpl.tell()
1974 line = tmpl.readline()
1975 started_subrun_reading = False
1976 while line!='':
1977
1978 if line.strip().startswith('!') or \
1979 line.strip().startswith('\n') or\
1980 line.strip() == '':
1981 output.write(line)
1982
1983 last_pos = tmpl.tell()
1984 line = tmpl.readline()
1985 continue
1986
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
1996 if param=='Main:subrun':
1997 if read_subrun:
1998 if not started_subrun_reading:
1999
2000 started_subrun_reading = True
2001 else:
2002
2003 tmpl.seek(last_pos)
2004 break
2005 else:
2006
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
2013 subruns.pop(subruns.index(int(value)))
2014 else:
2015
2016 DummySubrun=PY8SubRun()
2017
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
2027 last_pos = tmpl.tell()
2028 line = tmpl.readline()
2029 continue
2030
2031
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
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
2046 last_pos = tmpl.tell()
2047 line = tmpl.readline()
2048 continue
2049
2050
2051
2052
2053
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
2061
2062
2063 template = '!%s=%s'
2064
2065 output.write(template%(param_entry,
2066 value_entry.replace(value,new_value)))
2067
2068
2069 last_pos = tmpl.tell()
2070 line = tmpl.readline()
2071
2072
2073 if not add_missing:
2074 visible_param = []
2075 hidden_output_param = []
2076
2077
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
2112
2113 if read_subrun:
2114 output_file.write(output.getvalue())
2115 return
2116
2117
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
2124 for subrunID in sorted(subruns_to_write):
2125 output.write(subruns_to_write[subrunID].getvalue())
2126
2127
2128
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
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
2166 last_pos = finput.tell()
2167 line = finput.readline()
2168 started_subrun_reading = False
2169 while line!='':
2170
2171 if line.strip().startswith('!') or line.strip()=='':
2172
2173 last_pos = finput.tell()
2174 line = finput.readline()
2175 continue
2176
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
2189 if param=='Main:subrun':
2190 if read_subrun:
2191 if not started_subrun_reading:
2192
2193 started_subrun_reading = True
2194 else:
2195
2196 finput.seek(last_pos)
2197 return
2198 else:
2199
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
2206 NewSubrun=PY8SubRun()
2207 NewSubrun.read(finput,read_subrun=True, setter=setter)
2208 self.add_subrun(NewSubrun)
2209
2210
2211 last_pos = finput.tell()
2212 line = finput.readline()
2213 continue
2214
2215
2216
2217
2218
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
2227 last_pos = finput.tell()
2228 line = finput.readline()
2229
2231 """ Class to characterize a specific PY8 card subrun section. """
2232
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
2240 """ Initialize a subrun """
2241
2242
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
2251 """Sets up the list of available PY8SubRun parameters."""
2252
2253
2254 super(PY8SubRun, self).default_setup()
2255
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
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'))
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
2292
2293
2294
2295
2296 self.hidden_param = []
2297
2298 self.includepath = collections.defaultdict(list)
2299
2300 self.fortran_name = {}
2301
2302 self.legacy_parameter = {}
2303
2304
2305
2306
2307
2308 self.cuts_parameter = {}
2309
2310 self.system_default = {}
2311
2312 self.display_block = []
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
2377 self.add_param(name, float(value), hidden=True, cut=True)
2378 else:
2379 self.set( name, value, user=True)
2380
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
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
2429 write_block= []
2430 for b in self.blocks:
2431 name = b.name
2432
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
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
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
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
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):
2615
2616
2617 @staticmethod
2666
2667
2668
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
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
2698 self.check_validity()
2699
2700
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
2714 if key in self.fortran_name:
2715 fortran_name = self.fortran_name[key]
2716 else:
2717 fortran_name = key
2718
2719
2720 value = self.get_default(key)
2721
2722
2723 if isinstance(value, list):
2724
2725
2726
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
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
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
2758 return 0
2759 else:
2760 return lpp
2761
2776
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
2792
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
2812 """an object to handle in a nice way the run_card information"""
2813
2814 blocks = [
2815
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
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
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
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
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
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
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
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
2970 self.add_param("bias_module", 'None', include=False)
2971 self.add_param('bias_parameters', {'__type__':1.0}, include='BIAS/bias.inc')
2972
2973
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
3138
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)
3149 self.add_param('ptmin4pdg',[0.], system=True)
3150 self.add_param('ptmax4pdg',[-1.], system=True)
3151 self.add_param('Emin4pdg',[0.], system=True)
3152 self.add_param('Emax4pdg',[-1.], system=True)
3153 self.add_param('etamin4pdg',[0.], system=True)
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
3161 """ """
3162
3163 super(RunCardLO, self).check_validity()
3164
3165
3166
3167
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
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
3190 if self['gridrun']:
3191 self['iseed'] = self['gseed']
3192
3193
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
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
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
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
3236 if self['pdlabel'] == 'lhapdf':
3237
3238 self.get_default('lhaid', log_level=20)
3239
3240
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
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
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 fixed_fac_scale to be on True [since this is use as cutoff]")
3261
3262
3263 for i in [1,2]:
3264 if self['lpp%s' % i ] not in [1,2]:
3265 continue
3266 if self['mass_ion%i' % i] == -1:
3267 if self['ebeam%i' % i] < 0.938:
3268 if self['ebeam%i' %i] == 0:
3269 logger.warning("At rest proton mode set: Energy beam set to 0.938")
3270 self.set('ebeam%i' %i, 0.938)
3271 else:
3272 raise InvalidRunCard("Energy for beam %i lower than proton mass. Please fix this")
3273 elif self['ebeam%i' % i] < self['mass_ion%i' % i]:
3274 if self['ebeam%i' %i] == 0:
3275 logger.warning("At rest ion mode set: Energy beam set to %s" % self['mass_ion%i' % i])
3276 self.set('ebeam%i' %i, self['mass_ion%i' % i])
3277
3279
3280
3281 self['frame_id'] = sum(2**(n) for n in self['me_frame'])
3282
3283
3284 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys()) +
3285 list(self['e_min_pdg'].keys()) +list(self['e_max_pdg'].keys()) +
3286 list(self['eta_min_pdg'].keys()) +list(self['eta_max_pdg'].keys())+
3287 list(self['mxx_min_pdg'].keys()) + list(self['mxx_only_part_antipart'].keys()))
3288 pdg_to_cut.discard('__type__')
3289 pdg_to_cut.discard('default')
3290 if len(pdg_to_cut)>25:
3291 raise Exception("Maximum 25 different pdgs are allowed for pdg specific cut")
3292
3293 if any(int(pdg)<0 for pdg in pdg_to_cut):
3294 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
3295 raise MadGraph5Error('Some PDG specific cuts are defined with negative pdg code')
3296
3297
3298 if any(pdg in pdg_to_cut for pdg in [1,2,3,4,5,21,22,11,13,15]):
3299 raise Exception("Can not use PDG related cut for light quark/b quark/lepton/gluon/photon")
3300
3301 if pdg_to_cut:
3302 self['pdg_cut'] = list(pdg_to_cut)
3303 self['ptmin4pdg'] = []
3304 self['Emin4pdg'] = []
3305 self['etamin4pdg'] =[]
3306 self['ptmax4pdg'] = []
3307 self['Emax4pdg'] = []
3308 self['etamax4pdg'] =[]
3309 self['mxxmin4pdg'] =[]
3310 self['mxxpart_antipart'] = []
3311 for pdg in self['pdg_cut']:
3312 for var in ['pt','e','eta', 'Mxx']:
3313 for minmax in ['min', 'max']:
3314 if var in ['Mxx'] and minmax =='max':
3315 continue
3316 new_var = '%s%s4pdg' % (var, minmax)
3317 old_var = '%s_%s_pdg' % (var, minmax)
3318 default = 0. if minmax=='min' else -1.
3319 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3320
3321 old_var = 'mxx_only_part_antipart'
3322 new_var = 'mxxpart_antipart'
3323 if 'default' in self[old_var]:
3324 default = self[old_var]['default']
3325 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3326 else:
3327 if str(pdg) not in self[old_var]:
3328 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
3329 self[new_var].append(self[old_var][str(pdg)])
3330 else:
3331 self['pdg_cut'] = [0]
3332 self['ptmin4pdg'] = [0.]
3333 self['Emin4pdg'] = [0.]
3334 self['etamin4pdg'] =[0.]
3335 self['ptmax4pdg'] = [-1.]
3336 self['Emax4pdg'] = [-1.]
3337 self['etamax4pdg'] =[-1.]
3338 self['mxxmin4pdg'] =[0.]
3339 self['mxxpart_antipart'] = [False]
3340
3341
3342
3344 """Rules
3345 process 1->N all cut set on off.
3346 loop_induced -> MC over helicity
3347 e+ e- beam -> lpp:0 ebeam:500
3348 p p beam -> set maxjetflavor automatically
3349 more than one multiplicity: ickkw=1 xqcut=30 use_syst=F
3350 """
3351
3352 if proc_characteristic['loop_induced']:
3353 self['nhel'] = 1
3354 self['pdgs_for_merging_cut'] = proc_characteristic['colored_pdgs']
3355
3356 if proc_characteristic['ninitial'] == 1:
3357
3358 self.remove_all_cut()
3359 self['use_syst'] = False
3360 else:
3361
3362
3363 beam_id = set()
3364 beam_id_split = [set(), set()]
3365 for proc in proc_def:
3366 for oneproc in proc:
3367 for i,leg in enumerate(oneproc['legs']):
3368 if not leg['state']:
3369 beam_id_split[i].add(leg['id'])
3370 beam_id.add(leg['id'])
3371
3372 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3373 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
3374 self['maxjetflavor'] = maxjetflavor
3375 self['asrwgtflavor'] = maxjetflavor
3376
3377 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3378
3379 if any(id in beam_id for id in [11,-11,13,-13]):
3380 self.display_block.append('beam_pol')
3381 if any(id in beam_id_split[0] for id in [11,-11,13,-13]):
3382 self['lpp1'] = 0
3383 self['lpp2'] = 1
3384 self['ebeam1'] = '1k'
3385 self['ebeam2'] = '6500'
3386 else:
3387 self['lpp1'] = 1
3388 self['lpp2'] = 0
3389 self['ebeam1'] = '6500'
3390 self['ebeam2'] = '1k'
3391
3392 elif any(id in beam_id for id in [11,-11,13,-13]):
3393 self['lpp1'] = 0
3394 self['lpp2'] = 0
3395 self['ebeam1'] = 500
3396 self['ebeam2'] = 500
3397 self['use_syst'] = False
3398 if set([ abs(i) for i in beam_id_split[0]]) == set([ abs(i) for i in beam_id_split[1]]):
3399 self.display_block.append('ecut')
3400 self.display_block.append('beam_pol')
3401 else:
3402 self['lpp1'] = 0
3403 self['lpp2'] = 0
3404 self['use_syst'] = False
3405 self.display_block.append('beam_pol')
3406 self.display_block.append('ecut')
3407
3408
3409 if any(id in beam_id for id in [12,-12,14,-14,16,-16]):
3410 self.display_block.append('beam_pol')
3411 if any(id in beam_id_split[0] for id in [12,14,16]):
3412 self['lpp1'] = 0
3413 self['ebeam1'] = '1k'
3414 self['polbeam1'] = -100
3415 if not all(id in [12,14,16] for id in beam_id_split[0]):
3416 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1]. %s')
3417 elif any(id in beam_id_split[0] for id in [-12,-14,-16]):
3418 self['lpp1'] = 0
3419 self['ebeam1'] = '1k'
3420 self['polbeam1'] = 100
3421 if not all(id in [-12,-14,-16] for id in beam_id_split[0]):
3422 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1].')
3423 if any(id in beam_id_split[1] for id in [12,14,16]):
3424 self['lpp2'] = 0
3425 self['ebeam2'] = '1k'
3426 self['polbeam2'] = -100
3427 if not all(id in [12,14,16] for id in beam_id_split[1]):
3428 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].')
3429 if any(id in beam_id_split[1] for id in [-12,-14,-16]):
3430 self['lpp2'] = 0
3431 self['ebeam2'] = '1k'
3432 self['polbeam2'] = 100
3433 if not all(id in [-12,-14,-16] for id in beam_id_split[1]):
3434 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].')
3435
3436
3437 min_particle = 99
3438 max_particle = 0
3439 for proc in proc_def:
3440 min_particle = min(len(proc[0]['legs']), min_particle)
3441 max_particle = max(len(proc[0]['legs']), max_particle)
3442 if min_particle != max_particle:
3443
3444 for procmin in proc_def:
3445 if len(procmin[0]['legs']) != min_particle:
3446 continue
3447 else:
3448 idsmin = [l['id'] for l in procmin[0]['legs']]
3449 break
3450 matching = False
3451 for procmax in proc_def:
3452 if len(procmax[0]['legs']) != max_particle:
3453 continue
3454 idsmax = [l['id'] for l in procmax[0]['legs']]
3455 for i in idsmin:
3456 if i not in idsmax:
3457 continue
3458 else:
3459 idsmax.remove(i)
3460 for j in idsmax:
3461 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
3462 break
3463 else:
3464
3465 matching=True
3466 break
3467
3468 if matching:
3469 self['ickkw'] = 1
3470 self['xqcut'] = 30
3471
3472 self['drjj'] = 0
3473 self['drjl'] = 0
3474 self['sys_alpsfact'] = "0.5 1 2"
3475 self['systematics_arguments'].append('--alps=0.5,1,2')
3476 self.display_block.append('MLM')
3477 self.display_block.append('CKKW')
3478
3479
3480
3481 no_systematics = False
3482 interference = False
3483 for proc in proc_def:
3484 for oneproc in proc:
3485 if '^2' in oneproc.nice_string():
3486 interference = True
3487 break
3488 else:
3489 continue
3490 break
3491
3492
3493 if interference or no_systematics:
3494 self['use_syst'] = False
3495 self['systematics_program'] = 'none'
3496 if interference:
3497 self['dynamical_scale_choice'] = 3
3498
3499
3500
3501 for plist in proc_def:
3502 for proc in plist:
3503 for l in proc.get('legs') + proc.get('legs_with_decays'):
3504 if l.get('polarization'):
3505 model = proc.get('model')
3506 particle = model.get_particle(l.get('id'))
3507 if particle.get('mass').lower() != 'zero':
3508 self.display_block.append('frame')
3509 break
3510 else:
3511 continue
3512 break
3513 else:
3514 continue
3515 break
3516
3517 if 'MLM' in proc_characteristic['limitations']:
3518 if self['dynamical_scale_choice'] == -1:
3519 self['dynamical_scale_choice'] = 3
3520 if self['ickkw'] == 1:
3521 logger.critical("MLM matching/merging not compatible with the model! You need to use another method to remove the double counting!")
3522 self['ickkw'] = 0
3523
3524
3525
3526 cut_class = collections.defaultdict(int)
3527 for proc in proc_def:
3528 for oneproc in proc:
3529 one_proc_cut = collections.defaultdict(int)
3530 ids = oneproc.get_final_ids_after_decay()
3531 if oneproc['decay_chains']:
3532 cut_class['d'] = 1
3533 for pdg in ids:
3534 if pdg == 22:
3535 one_proc_cut['a'] +=1
3536 elif abs(pdg) <= self['maxjetflavor']:
3537 one_proc_cut['j'] += 1
3538 one_proc_cut['J'] += 1
3539 elif abs(pdg) <= 5:
3540 one_proc_cut['b'] += 1
3541 one_proc_cut['J'] += 1
3542 elif abs(pdg) in [11,13,15]:
3543 one_proc_cut['l'] += 1
3544 one_proc_cut['L'] += 1
3545 elif abs(pdg) in [12,14,16]:
3546 one_proc_cut['n'] += 1
3547 one_proc_cut['L'] += 1
3548 elif str(oneproc.get('model').get_particle(pdg)['mass']) != 'ZERO':
3549 one_proc_cut['H'] += 1
3550
3551 for key, nb in one_proc_cut.items():
3552 cut_class[key] = max(cut_class[key], nb)
3553 self.cut_class = dict(cut_class)
3554 self.cut_class[''] = True
3555
3556 - def write(self, output_file, template=None, python_template=False,
3557 **opt):
3558 """Write the run_card in output_file according to template
3559 (a path to a valid run_card)"""
3560
3561 if not template:
3562 if not MADEVENT:
3563 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
3564 'run_card.dat')
3565 python_template = True
3566 else:
3567 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
3568 python_template = False
3569
3570
3571 hid_lines = {'default':True}
3572 if isinstance(output_file, str):
3573 if 'default' in output_file:
3574 if self.cut_class:
3575 hid_lines['default'] = False
3576 for key in self.cut_class:
3577 nb = self.cut_class[key]
3578 for i in range(1,nb+1):
3579 hid_lines[key*i] = True
3580 for k1,k2 in ['bj', 'bl', 'al', 'jl', 'ab', 'aj']:
3581 if self.cut_class.get(k1) and self.cut_class.get(k2):
3582 hid_lines[k1+k2] = True
3583
3584 super(RunCardLO, self).write(output_file, template=template,
3585 python_template=python_template,
3586 template_options=hid_lines,
3587 **opt)
3588
3592
3594 """ A class to store a MadAnalysis5 card. Very basic since it is basically
3595 free format."""
3596
3597 _MG5aMC_escape_tag = '@MG5aMC'
3598
3599 _default_hadron_inputs = ['*.hepmc', '*.hep', '*.stdhep', '*.lhco','*.root']
3600 _default_parton_inputs = ['*.lhe']
3601 _skip_analysis = False
3602
3603 @classmethod
3605 """ Checks from the type of an event file whether it can be reconstructed or not."""
3606 return not (file_path.endswith('.lhco') or file_path.endswith('.lhco.gz') or \
3607 file_path.endswith('.root') or file_path.endswith('.root.gz'))
3608
3609 @classmethod
3611 """ A method returning the structure of an empty analysis """
3612 return {'commands':[],
3613 'reconstructions':[]}
3614
3615 @classmethod
3617 """ A method returning the structure of an empty reconstruction """
3618 return {'commands':[],
3619 'reco_output':'lhe'}
3620
3622 """define the default value"""
3623 self['mode'] = 'parton'
3624 self['inputs'] = []
3625
3626 self['stdout_lvl'] = None
3627
3628
3629
3630
3631
3632
3633
3634 self['analyses'] = {}
3635
3636
3637 self['recasting'] = {'commands':[],'card':[]}
3638
3639
3640 self['reconstruction'] = {'lhco_input':
3641 MadAnalysis5Card.empty_reconstruction(),
3642 'root_input':
3643 MadAnalysis5Card.empty_reconstruction()}
3644 self['reconstruction']['lhco_input']['reco_output']='lhco'
3645 self['reconstruction']['root_input']['reco_output']='root'
3646
3647
3648 self['order'] = []
3649
3650 - def __init__(self, finput=None,mode=None):
3651 if isinstance(finput, self.__class__):
3652 dict.__init__(self, finput)
3653 assert list(finput.__dict__.keys())
3654 for key in finput.__dict__:
3655 setattr(self, key, copy.copy(getattr(finput, key)) )
3656 return
3657 else:
3658 dict.__init__(self)
3659
3660
3661 self.default_setup()
3662 if not mode is None:
3663 self['mode']=mode
3664
3665
3666 if isinstance(finput, (file, str, StringIO.StringIO)):
3667 self.read(finput, mode=mode)
3668
3669 - def read(self, input, mode=None):
3670 """ Read an MA5 card"""
3671
3672 if mode not in [None,'parton','hadron']:
3673 raise MadGraph5Error('A MadAnalysis5Card can be read online the modes'+
3674 "'parton' or 'hadron'")
3675 card_mode = mode
3676
3677 if isinstance(input, (file, StringIO.StringIO)):
3678 input_stream = input
3679 elif isinstance(input, str):
3680 if not os.path.isfile(input):
3681 raise InvalidMadAnalysis5Card("Cannot read the MadAnalysis5 card."+\
3682 "File '%s' not found."%input)
3683 if mode is None and 'hadron' in input:
3684 card_mode = 'hadron'
3685 input_stream = open(input,'r')
3686 else:
3687 raise MadGraph5Error('Incorrect input for the read function of'+\
3688 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(input)))
3689
3690
3691 self.__init__()
3692 current_name = 'default'
3693 current_type = 'analyses'
3694 for line in input_stream:
3695
3696 if line.startswith('#'):
3697 continue
3698 if line.endswith('\n'):
3699 line = line[:-1]
3700 if line.strip()=='':
3701 continue
3702 if line.startswith(self._MG5aMC_escape_tag):
3703 try:
3704 option,value = line[len(self._MG5aMC_escape_tag):].split('=')
3705 value = value.strip()
3706 except ValueError:
3707 option = line[len(self._MG5aMC_escape_tag):]
3708 option = option.strip()
3709
3710 if option=='inputs':
3711 self['inputs'].extend([v.strip() for v in value.split(',')])
3712
3713 elif option == 'skip_analysis':
3714 self._skip_analysis = True
3715
3716 elif option=='stdout_lvl':
3717 try:
3718 self['stdout_lvl']=int(value)
3719 except ValueError:
3720 try:
3721 self['stdout_lvl']=eval(value)
3722 except:
3723 try:
3724 self['stdout_lvl']=eval('logging.%s'%value)
3725 except:
3726 raise InvalidMadAnalysis5Card(
3727 "MA5 output level specification '%s' is incorrect."%str(value))
3728
3729 elif option=='analysis_name':
3730 current_type = 'analyses'
3731 current_name = value
3732 if current_name in self[current_type]:
3733 raise InvalidMadAnalysis5Card(
3734 "Analysis '%s' already defined in MadAnalysis5 card"%current_name)
3735 else:
3736 self[current_type][current_name] = MadAnalysis5Card.empty_analysis()
3737
3738 elif option=='set_reconstructions':
3739 try:
3740 reconstructions = eval(value)
3741 if not isinstance(reconstructions, list):
3742 raise
3743 except:
3744 raise InvalidMadAnalysis5Card("List of reconstructions"+\
3745 " '%s' could not be parsed in MadAnalysis5 card."%value)
3746 if current_type!='analyses' and current_name not in self[current_type]:
3747 raise InvalidMadAnalysis5Card("A list of reconstructions"+\
3748 "can only be defined in the context of an "+\
3749 "analysis in a MadAnalysis5 card.")
3750 self[current_type][current_name]['reconstructions']=reconstructions
3751 continue
3752
3753 elif option=='reconstruction_name':
3754 current_type = 'reconstruction'
3755 current_name = value
3756 if current_name in self[current_type]:
3757 raise InvalidMadAnalysis5Card(
3758 "Reconstruction '%s' already defined in MadAnalysis5 hadron card"%current_name)
3759 else:
3760 self[current_type][current_name] = MadAnalysis5Card.empty_reconstruction()
3761
3762 elif option=='reco_output':
3763 if current_type!='reconstruction' or current_name not in \
3764 self['reconstruction']:
3765 raise InvalidMadAnalysis5Card(
3766 "Option '%s' is only available within the definition of a reconstruction"%option)
3767 if not value.lower() in ['lhe','root']:
3768 raise InvalidMadAnalysis5Card(
3769 "Option '%s' can only take the values 'lhe' or 'root'"%option)
3770 self['reconstruction'][current_name]['reco_output'] = value.lower()
3771
3772 elif option.startswith('recasting'):
3773 current_type = 'recasting'
3774 try:
3775 current_name = option.split('_')[1]
3776 except:
3777 raise InvalidMadAnalysis5Card('Malformed MA5 recasting option %s.'%option)
3778 if len(self['recasting'][current_name])>0:
3779 raise InvalidMadAnalysis5Card(
3780 "Only one recasting can be defined in MadAnalysis5 hadron card")
3781
3782 else:
3783 raise InvalidMadAnalysis5Card(
3784 "Unreckognized MG5aMC instruction in MadAnalysis5 card: '%s'"%option)
3785
3786 if option in ['analysis_name','reconstruction_name'] or \
3787 option.startswith('recasting'):
3788 self['order'].append((current_type,current_name))
3789 continue
3790
3791
3792
3793 if current_name == 'default' and current_type == 'analyses' and\
3794 'default' not in self['analyses']:
3795 self['analyses']['default'] = MadAnalysis5Card.empty_analysis()
3796 self['order'].append(('analyses','default'))
3797
3798 if current_type in ['recasting']:
3799 self[current_type][current_name].append(line)
3800 elif current_type in ['reconstruction']:
3801 self[current_type][current_name]['commands'].append(line)
3802 elif current_type in ['analyses']:
3803 self[current_type][current_name]['commands'].append(line)
3804
3805 if 'reconstruction' in self['analyses'] or len(self['recasting']['card'])>0:
3806 if mode=='parton':
3807 raise InvalidMadAnalysis5Card(
3808 "A parton MadAnalysis5 card cannot specify a recombination or recasting.")
3809 card_mode = 'hadron'
3810 elif mode is None:
3811 card_mode = 'parton'
3812
3813 self['mode'] = card_mode
3814 if self['inputs'] == []:
3815 if self['mode']=='hadron':
3816 self['inputs'] = self._default_hadron_inputs
3817 else:
3818 self['inputs'] = self._default_parton_inputs
3819
3820
3821
3822 if self['mode']=='hadron':
3823 for analysis_name, analysis in self['analyses'].items():
3824 if len(analysis['reconstructions'])==0:
3825 raise InvalidMadAnalysis5Card('Hadron-level analysis '+\
3826 "'%s' is not specified any reconstruction(s)."%analysis_name)
3827 if any(reco not in self['reconstruction'] for reco in \
3828 analysis['reconstructions']):
3829 raise InvalidMadAnalysis5Card('A reconstructions specified in'+\
3830 " analysis '%s' is not defined."%analysis_name)
3831
3832 - def write(self, output):
3833 """ Write an MA5 card."""
3834
3835 if isinstance(output, (file, StringIO.StringIO)):
3836 output_stream = output
3837 elif isinstance(output, str):
3838 output_stream = open(output,'w')
3839 else:
3840 raise MadGraph5Error('Incorrect input for the write function of'+\
3841 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(output)))
3842
3843 output_lines = []
3844 if self._skip_analysis:
3845 output_lines.append('%s skip_analysis'%self._MG5aMC_escape_tag)
3846 output_lines.append('%s inputs = %s'%(self._MG5aMC_escape_tag,','.join(self['inputs'])))
3847 if not self['stdout_lvl'] is None:
3848 output_lines.append('%s stdout_lvl=%s'%(self._MG5aMC_escape_tag,self['stdout_lvl']))
3849 for definition_type, name in self['order']:
3850
3851 if definition_type=='analyses':
3852 output_lines.append('%s analysis_name = %s'%(self._MG5aMC_escape_tag,name))
3853 output_lines.append('%s set_reconstructions = %s'%(self._MG5aMC_escape_tag,
3854 str(self['analyses'][name]['reconstructions'])))
3855 elif definition_type=='reconstruction':
3856 output_lines.append('%s reconstruction_name = %s'%(self._MG5aMC_escape_tag,name))
3857 elif definition_type=='recasting':
3858 output_lines.append('%s recasting_%s'%(self._MG5aMC_escape_tag,name))
3859
3860 if definition_type in ['recasting']:
3861 output_lines.extend(self[definition_type][name])
3862 elif definition_type in ['reconstruction']:
3863 output_lines.append('%s reco_output = %s'%(self._MG5aMC_escape_tag,
3864 self[definition_type][name]['reco_output']))
3865 output_lines.extend(self[definition_type][name]['commands'])
3866 elif definition_type in ['analyses']:
3867 output_lines.extend(self[definition_type][name]['commands'])
3868
3869 output_stream.write('\n'.join(output_lines))
3870
3871 return
3872
3873 - def get_MA5_cmds(self, inputs_arg, submit_folder, run_dir_path=None,
3874 UFO_model_path=None, run_tag=''):
3875 """ Returns a list of tuples ('AnalysisTag',['commands']) specifying
3876 the commands of the MadAnalysis runs required from this card.
3877 At parton-level, the number of such commands is the number of analysis
3878 asked for. In the future, the idea is that the entire card can be
3879 processed in one go from MA5 directly."""
3880
3881 if isinstance(inputs_arg, list):
3882 inputs = inputs_arg
3883 elif isinstance(inputs_arg, str):
3884 inputs = [inputs_arg]
3885 else:
3886 raise MadGraph5Error("The function 'get_MA5_cmds' can only take "+\
3887 " a string or a list for the argument 'inputs_arg'")
3888
3889 if len(inputs)==0:
3890 raise MadGraph5Error("The function 'get_MA5_cmds' must have "+\
3891 " at least one input specified'")
3892
3893 if run_dir_path is None:
3894 run_dir_path = os.path.dirname(inputs_arg)
3895
3896 cmds_list = []
3897
3898 UFO_load = []
3899
3900 if UFO_model_path:
3901 UFO_load.append('import %s'%UFO_model_path)
3902
3903 def get_import(input, type=None):
3904 """ Generates the MA5 import commands for that event file. """
3905 dataset_name = os.path.basename(input).split('.')[0]
3906 res = ['import %s as %s'%(input, dataset_name)]
3907 if not type is None:
3908 res.append('set %s.type = %s'%(dataset_name, type))
3909 return res
3910
3911 fifo_status = {'warned_fifo':False,'fifo_used_up':False}
3912 def warn_fifo(input):
3913 if not input.endswith('.fifo'):
3914 return False
3915 if not fifo_status['fifo_used_up']:
3916 fifo_status['fifo_used_up'] = True
3917 return False
3918 else:
3919 if not fifo_status['warned_fifo']:
3920 logger.warning('Only the first MA5 analysis/reconstructions can be run on a fifo. Subsequent runs will skip fifo inputs.')
3921 fifo_status['warned_fifo'] = True
3922 return True
3923
3924
3925 inputs_load = []
3926 for input in inputs:
3927 inputs_load.extend(get_import(input))
3928
3929 submit_command = 'submit %s'%submit_folder+'_%s'
3930
3931
3932
3933
3934 reconstruction_outputs = {
3935 'lhco_input':[f for f in inputs if
3936 f.endswith('.lhco') or f.endswith('.lhco.gz')],
3937 'root_input':[f for f in inputs if
3938 f.endswith('.root') or f.endswith('.root.gz')]}
3939
3940
3941 recasting_card_path = pjoin(run_dir_path,
3942 '_'.join([run_tag,os.path.basename(submit_folder),'recasting_card.dat']))
3943
3944
3945 for definition_type, name in self['order']:
3946 if definition_type == 'reconstruction':
3947 analysis_cmds = list(self['reconstruction'][name]['commands'])
3948 reco_outputs = []
3949 for i_input, input in enumerate(inputs):
3950
3951 if not MadAnalysis5Card.events_can_be_reconstructed(input):
3952 continue
3953
3954 if warn_fifo(input):
3955 continue
3956 analysis_cmds.append('import %s as reco_events'%input)
3957 if self['reconstruction'][name]['reco_output']=='lhe':
3958 reco_outputs.append('%s_%s.lhe.gz'%(os.path.basename(
3959 input).replace('_events','').split('.')[0],name))
3960 analysis_cmds.append('set main.outputfile=%s'%reco_outputs[-1])
3961 elif self['reconstruction'][name]['reco_output']=='root':
3962 reco_outputs.append('%s_%s.root'%(os.path.basename(
3963 input).replace('_events','').split('.')[0],name))
3964 analysis_cmds.append('set main.fastsim.rootfile=%s'%reco_outputs[-1])
3965 analysis_cmds.append(
3966 submit_command%('reco_%s_%d'%(name,i_input+1)))
3967 analysis_cmds.append('remove reco_events')
3968
3969 reconstruction_outputs[name]= [pjoin(run_dir_path,rec_out)
3970 for rec_out in reco_outputs]
3971 if len(reco_outputs)>0:
3972 cmds_list.append(('_reco_%s'%name,analysis_cmds))
3973
3974 elif definition_type == 'analyses':
3975 if self['mode']=='parton':
3976 cmds_list.append( (name, UFO_load+inputs_load+
3977 self['analyses'][name]['commands']+[submit_command%name]) )
3978 elif self['mode']=='hadron':
3979
3980 for reco in self['analyses'][name]['reconstructions']+\
3981 ['lhco_input','root_input']:
3982 if len(reconstruction_outputs[reco])==0:
3983 continue
3984 if self['reconstruction'][reco]['reco_output']=='lhe':
3985
3986 analysis_cmds = ['set main.mode = parton']
3987 else:
3988 analysis_cmds = []
3989 analysis_cmds.extend(sum([get_import(rec_out) for
3990 rec_out in reconstruction_outputs[reco]],[]))
3991 analysis_cmds.extend(self['analyses'][name]['commands'])
3992 analysis_cmds.append(submit_command%('%s_%s'%(name,reco)))
3993 cmds_list.append( ('%s_%s'%(name,reco),analysis_cmds) )
3994
3995 elif definition_type == 'recasting':
3996 if len(self['recasting']['card'])==0:
3997 continue
3998 if name == 'card':
3999
4000 open(recasting_card_path,'w').write('\n'.join(self['recasting']['card']))
4001 if name == 'commands':
4002 recasting_cmds = list(self['recasting']['commands'])
4003
4004 n_inputs = 0
4005 for input in inputs:
4006 if not MadAnalysis5Card.events_can_be_reconstructed(input):
4007 continue
4008
4009 if warn_fifo(input):
4010 continue
4011 recasting_cmds.extend(get_import(input,'signal'))
4012 n_inputs += 1
4013
4014 recasting_cmds.append('set main.recast.card_path=%s'%recasting_card_path)
4015 recasting_cmds.append(submit_command%'Recasting')
4016 if n_inputs>0:
4017 cmds_list.append( ('Recasting',recasting_cmds))
4018
4019 return cmds_list
4020
4022 """A class object for the run_card for a (aMC@)NLO pocess"""
4023
4025 """define the default value"""
4026
4027 self.add_param('run_tag', 'tag_1', include=False)
4028 self.add_param('nevents', 10000)
4029 self.add_param('req_acc', -1.0, include=False)
4030 self.add_param('nevt_job', -1, include=False)
4031 self.add_param('event_norm', 'average')
4032
4033 self.add_param('req_acc_fo', 0.01, include=False)
4034 self.add_param('npoints_fo_grid', 5000, include=False)
4035 self.add_param('niters_fo_grid', 4, include=False)
4036 self.add_param('npoints_fo', 10000, include=False)
4037 self.add_param('niters_fo', 6, include=False)
4038
4039 self.add_param('iseed', 0)
4040 self.add_param('lpp1', 1, fortran_name='lpp(1)')
4041 self.add_param('lpp2', 1, fortran_name='lpp(2)')
4042 self.add_param('ebeam1', 6500.0, fortran_name='ebeam(1)')
4043 self.add_param('ebeam2', 6500.0, fortran_name='ebeam(2)')
4044 self.add_param('pdlabel', 'nn23nlo', allowed=['lhapdf', 'cteq6_m','cteq6_d','cteq6_l','cteq6l1', 'nn23lo','nn23lo1','nn23nlo'])
4045 self.add_param('lhaid', [244600],fortran_name='lhaPDFid')
4046 self.add_param('lhapdfsetname', ['internal_use_only'], system=True)
4047
4048 self.add_param('parton_shower', 'HERWIG6', fortran_name='shower_mc')
4049 self.add_param('shower_scale_factor',1.0)
4050 self.add_param('fixed_ren_scale', False)
4051 self.add_param('fixed_fac_scale', False)
4052 self.add_param('mur_ref_fixed', 91.118)
4053 self.add_param('muf1_ref_fixed', -1.0, hidden=True)
4054 self.add_param('muf_ref_fixed', 91.118)
4055 self.add_param('muf2_ref_fixed', -1.0, hidden=True)
4056 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")
4057 self.add_param('fixed_qes_scale', False, hidden=True)
4058 self.add_param('qes_ref_fixed', -1.0, hidden=True)
4059 self.add_param('mur_over_ref', 1.0)
4060 self.add_param('muf_over_ref', 1.0)
4061 self.add_param('muf1_over_ref', -1.0, hidden=True)
4062 self.add_param('muf2_over_ref', -1.0, hidden=True)
4063 self.add_param('qes_over_ref', -1.0, hidden=True)
4064 self.add_param('reweight_scale', [True], fortran_name='lscalevar')
4065 self.add_param('rw_rscale_down', -1.0, hidden=True)
4066 self.add_param('rw_rscale_up', -1.0, hidden=True)
4067 self.add_param('rw_fscale_down', -1.0, hidden=True)
4068 self.add_param('rw_fscale_up', -1.0, hidden=True)
4069 self.add_param('rw_rscale', [1.0,2.0,0.5], fortran_name='scalevarR')
4070 self.add_param('rw_fscale', [1.0,2.0,0.5], fortran_name='scalevarF')
4071 self.add_param('reweight_pdf', [False], fortran_name='lpdfvar')
4072 self.add_param('pdf_set_min', 244601, hidden=True)
4073 self.add_param('pdf_set_max', 244700, hidden=True)
4074 self.add_param('store_rwgt_info', False)
4075 self.add_param('systematics_program', 'none', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics')
4076 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.')
4077
4078
4079 self.add_param('ickkw', 0, allowed=[-1,0,3,4], comment=" - 0: No merging\n - 3: FxFx Merging : http://amcatnlo.cern.ch/FxFx_merging.htm\n - 4: UNLOPS merging (No interface within MG5aMC)\n - -1: NNLL+NLO jet-veto computation. See arxiv:1412.8408 [hep-ph]")
4080 self.add_param('bwcutoff', 15.0)
4081
4082 self.add_param('jetalgo', 1.0)
4083 self.add_param('jetradius', 0.7)
4084 self.add_param('ptj', 10.0 , cut=True)
4085 self.add_param('etaj', -1.0, cut=True)
4086 self.add_param('ptl', 0.0, cut=True)
4087 self.add_param('etal', -1.0, cut=True)
4088 self.add_param('drll', 0.0, cut=True)
4089 self.add_param('drll_sf', 0.0, cut=True)
4090 self.add_param('mll', 0.0, cut=True)
4091 self.add_param('mll_sf', 30.0, cut=True)
4092 self.add_param('ptgmin', 20.0, cut=True)
4093 self.add_param('etagamma', -1.0)
4094 self.add_param('r0gamma', 0.4)
4095 self.add_param('xn', 1.0)
4096 self.add_param('epsgamma', 1.0)
4097 self.add_param('isoem', True)
4098 self.add_param('maxjetflavor', 4, hidden=True)
4099 self.add_param('iappl', 0)
4100 self.add_param('lhe_version', 3, hidden=True, include=False)
4101
4102
4103 self.add_param('FO_LHE_weight_ratio',1e-3, hidden=True, system=True)
4104 self.add_param('FO_LHE_postprocessing',['grouping','random'],
4105 hidden=True, system=True, include=False)
4106
4107
4108 self.add_param('pt_min_pdg',{'__type__':0.}, include=False,cut=True)
4109 self.add_param('pt_max_pdg',{'__type__':0.}, include=False,cut=True)
4110 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True)
4111 self.add_param('mxx_only_part_antipart', {'default':False}, include=False, hidden=True)
4112
4113
4114 self.add_param('pdg_cut',[0], hidden=True, system=True)
4115 self.add_param('ptmin4pdg',[0.], hidden=True, system=True)
4116 self.add_param('ptmax4pdg',[-1.], hidden=True, system=True)
4117 self.add_param('mxxmin4pdg',[0.], hidden=True, system=True)
4118 self.add_param('mxxpart_antipart', [False], hidden=True, system=True)
4119
4121 """check the validity of the various input"""
4122
4123 super(RunCardNLO, self).check_validity()
4124
4125
4126 if abs(self['lpp1'])!=1 or abs(self['lpp2'])!=1:
4127 if self['lpp1'] == 1 or self['lpp2']==1:
4128 raise InvalidRunCard('Process like Deep Inelastic scattering not supported at NLO accuracy.')
4129
4130 if self['pdlabel']!='nn23nlo' or self['reweight_pdf']:
4131 self['pdlabel']='nn23nlo'
4132 self['reweight_pdf']=[False]
4133 logger.info('''Lepton-lepton collisions: ignoring PDF related parameters in the run_card.dat (pdlabel, lhaid, reweight_pdf, ...)''')
4134
4135
4136 if self['ickkw'] == 3:
4137
4138 scales=['fixed_ren_scale','fixed_fac_scale','fixed_QES_scale']
4139 for scale in scales:
4140 if self[scale]:
4141 logger.warning('''For consistency in the FxFx merging, \'%s\' has been set to false'''
4142 % scale,'$MG:BOLD')
4143 self[scale]= False
4144
4145 if len(self["dynamical_scale_choice"]) > 1 or self["dynamical_scale_choice"][0] != -1:
4146 self["dynamical_scale_choice"] = [-1]
4147 self["reweight_scale"]=[self["reweight_scale"][0]]
4148 logger.warning('''For consistency in the FxFx merging, dynamical_scale_choice has been set to -1 (default)'''
4149 ,'$MG:BOLD')
4150
4151
4152 jetparams=['jetradius','jetalgo']
4153 for jetparam in jetparams:
4154 if float(self[jetparam]) != 1.0:
4155 logger.info('''For consistency in the FxFx merging, \'%s\' has been set to 1.0'''
4156 % jetparam ,'$MG:BOLD')
4157 self[jetparam] = 1.0
4158 elif self['ickkw'] == -1 and (self["dynamical_scale_choice"][0] != -1 or
4159 len(self["dynamical_scale_choice"]) > 1):
4160 self["dynamical_scale_choice"] = [-1]
4161 self["reweight_scale"]=[self["reweight_scale"][0]]
4162 logger.warning('''For consistency with the jet veto, the scale which will be used is ptj. dynamical_scale_choice will be set at -1.'''
4163 ,'$MG:BOLD')
4164
4165
4166 if self['iappl'] != 0 and self['pdlabel'].lower() != 'lhapdf':
4167 raise InvalidRunCard('APPLgrid generation only possible with the use of LHAPDF')
4168 if self['iappl'] != 0 and not self['reweight_scale']:
4169 raise InvalidRunCard('APPLgrid generation only possible with including' +\
4170 ' the reweighting to get scale dependence')
4171
4172
4173 if self['qes_ref_fixed'] == -1.0:
4174 self['qes_ref_fixed']=self['mur_ref_fixed']
4175 if self['qes_over_ref'] == -1.0:
4176 self['qes_over_ref']=self['mur_over_ref']
4177 if self['muf1_over_ref'] != -1.0 and self['muf1_over_ref'] == self['muf2_over_ref']:
4178 self['muf_over_ref']=self['muf1_over_ref']
4179 if self['muf1_over_ref'] == -1.0:
4180 self['muf1_over_ref']=self['muf_over_ref']
4181 if self['muf2_over_ref'] == -1.0:
4182 self['muf2_over_ref']=self['muf_over_ref']
4183 if self['muf1_ref_fixed'] != -1.0 and self['muf1_ref_fixed'] == self['muf2_ref_fixed']:
4184 self['muf_ref_fixed']=self['muf1_ref_fixed']
4185 if self['muf1_ref_fixed'] == -1.0:
4186 self['muf1_ref_fixed']=self['muf_ref_fixed']
4187 if self['muf2_ref_fixed'] == -1.0:
4188 self['muf2_ref_fixed']=self['muf_ref_fixed']
4189
4190 if (self['rw_rscale_down'] != -1.0 and ['rw_rscale_down'] not in self['rw_rscale']) or\
4191 (self['rw_rscale_up'] != -1.0 and ['rw_rscale_up'] not in self['rw_rscale']):
4192 self['rw_rscale']=[1.0,self['rw_rscale_up'],self['rw_rscale_down']]
4193 if (self['rw_fscale_down'] != -1.0 and ['rw_fscale_down'] not in self['rw_fscale']) or\
4194 (self['rw_fscale_up'] != -1.0 and ['rw_fscale_up'] not in self['rw_fscale']):
4195 self['rw_fscale']=[1.0,self['rw_fscale_up'],self['rw_fscale_down']]
4196
4197
4198 if any(self['reweight_pdf']):
4199
4200 if self['pdlabel'] != "lhapdf":
4201 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.')
4202
4203
4204 if self['pdlabel'] != "lhapdf":
4205 self['reweight_pdf']=[self['reweight_pdf'][0]]
4206 self['lhaid']=[self['lhaid'][0]]
4207
4208
4209 if self['fixed_ren_scale'] and self['fixed_fac_scale']:
4210 self['reweight_scale']=[self['reweight_scale'][0]]
4211 self['dynamical_scale_choice']=[0]
4212
4213
4214
4215
4216 if len(self['reweight_pdf']) == 1 and len(self['lhaid']) != 1:
4217 self['reweight_pdf']=self['reweight_pdf']*len(self['lhaid'])
4218 logger.warning("Setting 'reweight_pdf' for all 'lhaid' to %s" % self['reweight_pdf'][0])
4219 if len(self['reweight_scale']) == 1 and len(self['dynamical_scale_choice']) != 1:
4220 self['reweight_scale']=self['reweight_scale']*len(self['dynamical_scale_choice'])
4221 logger.warning("Setting 'reweight_scale' for all 'dynamical_scale_choice' to %s" % self['reweight_pdf'][0])
4222
4223
4224 if len(self['lhaid']) != len(set(self['lhaid'])):
4225 raise InvalidRunCard("'lhaid' has two or more identical entries. They have to be all different for the code to work correctly.")
4226 if len(self['dynamical_scale_choice']) != len(set(self['dynamical_scale_choice'])):
4227 raise InvalidRunCard("'dynamical_scale_choice' has two or more identical entries. They have to be all different for the code to work correctly.")
4228
4229
4230 if len(self['reweight_pdf']) != len(self['lhaid']):
4231 raise InvalidRunCard("'reweight_pdf' and 'lhaid' lists should have the same length")
4232 if len(self['reweight_scale']) != len(self['dynamical_scale_choice']):
4233 raise InvalidRunCard("'reweight_scale' and 'dynamical_scale_choice' lists should have the same length")
4234 if len(self['dynamical_scale_choice']) > 10 :
4235 raise InvalidRunCard("Length of list for 'dynamical_scale_choice' too long: max is 10.")
4236 if len(self['lhaid']) > 25 :
4237 raise InvalidRunCard("Length of list for 'lhaid' too long: max is 25.")
4238 if len(self['rw_rscale']) > 9 :
4239 raise InvalidRunCard("Length of list for 'rw_rscale' too long: max is 9.")
4240 if len(self['rw_fscale']) > 9 :
4241 raise InvalidRunCard("Length of list for 'rw_fscale' too long: max is 9.")
4242
4243 if 1.0 not in self['rw_rscale']:
4244 logger.warning("'1.0' has to be part of 'rw_rscale', adding it")
4245 self['rw_rscale'].insert(0,1.0)
4246 if 1.0 not in self['rw_fscale']:
4247 logger.warning("'1.0' has to be part of 'rw_fscale', adding it")
4248 self['rw_fscale'].insert(0,1.0)
4249 if self['rw_rscale'][0] != 1.0 and 1.0 in self['rw_rscale']:
4250 a=self['rw_rscale'].index(1.0)
4251 self['rw_rscale'][0],self['rw_rscale'][a]=self['rw_rscale'][a],self['rw_rscale'][0]
4252 if self['rw_fscale'][0] != 1.0 and 1.0 in self['rw_fscale']:
4253 a=self['rw_fscale'].index(1.0)
4254 self['rw_fscale'][0],self['rw_fscale'][a]=self['rw_fscale'][a],self['rw_fscale'][0]
4255
4256 if len(self['rw_rscale']) != len(set(self['rw_rscale'])):
4257 raise InvalidRunCard("'rw_rscale' has two or more identical entries. They have to be all different for the code to work correctly.")
4258 if len(self['rw_fscale']) != len(set(self['rw_fscale'])):
4259 raise InvalidRunCard("'rw_fscale' has two or more identical entries. They have to be all different for the code to work correctly.")
4260
4261
4262
4263 for i in [1,2]:
4264 if self['lpp%s' % i ] not in [1,2]:
4265 continue
4266
4267 if self['ebeam%i' % i] < 0.938:
4268 if self['ebeam%i' %i] == 0:
4269 logger.warning("At rest proton mode set: Energy beam set to 0.938")
4270 self.set('ebeam%i' %i, 0.938)
4271 else:
4272 raise InvalidRunCard("Energy for beam %i lower than proton mass. Please fix this")
4273
4274
4276
4277
4278 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys())+
4279 list(self['mxx_min_pdg'].keys())+ list(self['mxx_only_part_antipart'].keys()))
4280 pdg_to_cut.discard('__type__')
4281 pdg_to_cut.discard('default')
4282 if len(pdg_to_cut)>25:
4283 raise Exception("Maximum 25 different PDGs are allowed for PDG specific cut")
4284
4285 if any(int(pdg)<0 for pdg in pdg_to_cut):
4286 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
4287 raise MadGraph5Error('Some PDG specific cuts are defined with negative PDG codes')
4288
4289
4290 if any(pdg in pdg_to_cut for pdg in [21,22,11,13,15]+ list(range(self['maxjetflavor']+1))):
4291
4292 raise Exception("Can not use PDG related cuts for massless SM particles/leptons")
4293 if pdg_to_cut:
4294 self['pdg_cut'] = list(pdg_to_cut)
4295 self['ptmin4pdg'] = []
4296 self['ptmax4pdg'] = []
4297 self['mxxmin4pdg'] = []
4298 self['mxxpart_antipart'] = []
4299 for pdg in self['pdg_cut']:
4300 for var in ['pt','mxx']:
4301 for minmax in ['min', 'max']:
4302 if var == 'mxx' and minmax == 'max':
4303 continue
4304 new_var = '%s%s4pdg' % (var, minmax)
4305 old_var = '%s_%s_pdg' % (var, minmax)
4306 default = 0. if minmax=='min' else -1.
4307 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4308
4309 old_var = 'mxx_only_part_antipart'
4310 new_var = 'mxxpart_antipart'
4311 if 'default' in self[old_var]:
4312 default = self[old_var]['default']
4313 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4314 else:
4315 if str(pdg) not in self[old_var]:
4316 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
4317 self[new_var].append(self[old_var][str(pdg)])
4318 else:
4319 self['pdg_cut'] = [0]
4320 self['ptmin4pdg'] = [0.]
4321 self['ptmax4pdg'] = [-1.]
4322 self['mxxmin4pdg'] = [0.]
4323 self['mxxpart_antipart'] = [False]
4324
4325 - def write(self, output_file, template=None, python_template=False, **opt):
4326 """Write the run_card in output_file according to template
4327 (a path to a valid run_card)"""
4328
4329 if not template:
4330 if not MADEVENT:
4331 template = pjoin(MG5DIR, 'Template', 'NLO', 'Cards',
4332 'run_card.dat')
4333 python_template = True
4334 else:
4335 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
4336 python_template = False
4337
4338 super(RunCardNLO, self).write(output_file, template=template,
4339 python_template=python_template, **opt)
4340
4341
4343 """Rules
4344 e+ e- beam -> lpp:0 ebeam:500
4345 p p beam -> set maxjetflavor automatically
4346 """
4347
4348
4349 beam_id = set()
4350 for proc in proc_def:
4351 for leg in proc['legs']:
4352 if not leg['state']:
4353 beam_id.add(leg['id'])
4354 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
4355 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
4356 self['maxjetflavor'] = maxjetflavor
4357 pass
4358 elif any(id in beam_id for id in [11,-11,13,-13]):
4359 self['lpp1'] = 0
4360 self['lpp2'] = 0
4361 self['ebeam1'] = 500
4362 self['ebeam2'] = 500
4363 else:
4364 self['lpp1'] = 0
4365 self['lpp2'] = 0
4366
4367 if proc_characteristic['ninitial'] == 1:
4368
4369 self.remove_all_cut()
4370
4371
4372 min_particle = 99
4373 max_particle = 0
4374 for proc in proc_def:
4375 min_particle = min(len(proc['legs']), min_particle)
4376 max_particle = max(len(proc['legs']), max_particle)
4377 matching = False
4378 if min_particle != max_particle:
4379
4380 for procmin in proc_def:
4381 if len(procmin['legs']) != min_particle:
4382 continue
4383 else:
4384 idsmin = [l['id'] for l in procmin['legs']]
4385 break
4386
4387 for procmax in proc_def:
4388 if len(procmax['legs']) != max_particle:
4389 continue
4390 idsmax = [l['id'] for l in procmax['legs']]
4391 for i in idsmin:
4392 if i not in idsmax:
4393 continue
4394 else:
4395 idsmax.remove(i)
4396 for j in idsmax:
4397 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
4398 break
4399 else:
4400
4401 matching=True
4402 break
4403
4404 if matching:
4405 self['ickkw'] = 3
4406 self['fixed_ren_scale'] = False
4407 self["fixed_fac_scale"] = False
4408 self["fixed_QES_scale"] = False
4409 self["jetalgo"] = 1
4410 self["jetradius"] = 1
4411 self["parton_shower"] = "PYTHIA8"
4412
4417 """ a class for storing/dealing with the file MadLoopParam.dat
4418 contains a parser to read it, facilities to write a new file,...
4419 """
4420
4421 _ID_reduction_tool_map = {1:'CutTools',
4422 2:'PJFry++',
4423 3:'IREGI',
4424 4:'Golem95',
4425 5:'Samurai',
4426 6:'Ninja',
4427 7:'COLLIER'}
4428
4430 """initialize the directory to the default value"""
4431
4432 self.add_param("MLReductionLib", "6|7|1")
4433 self.add_param("IREGIMODE", 2)
4434 self.add_param("IREGIRECY", True)
4435 self.add_param("CTModeRun", -1)
4436 self.add_param("MLStabThres", 1e-3)
4437 self.add_param("NRotations_DP", 0)
4438 self.add_param("NRotations_QP", 0)
4439 self.add_param("ImprovePSPoint", 2)
4440 self.add_param("CTLoopLibrary", 2)
4441 self.add_param("CTStabThres", 1e-2)
4442 self.add_param("CTModeInit", 1)
4443 self.add_param("CheckCycle", 3)
4444 self.add_param("MaxAttempts", 10)
4445 self.add_param("ZeroThres", 1e-9)
4446 self.add_param("OSThres", 1.0e-8)
4447 self.add_param("DoubleCheckHelicityFilter", True)
4448 self.add_param("WriteOutFilters", True)
4449 self.add_param("UseLoopFilter", False)
4450 self.add_param("HelicityFilterLevel", 2)
4451 self.add_param("LoopInitStartOver", False)
4452 self.add_param("HelInitStartOver", False)
4453 self.add_param("UseQPIntegrandForNinja", True)
4454 self.add_param("UseQPIntegrandForCutTools", True)
4455 self.add_param("COLLIERMode", 1)
4456 self.add_param("COLLIERComputeUVpoles", True)
4457 self.add_param("COLLIERComputeIRpoles", True)
4458 self.add_param("COLLIERRequiredAccuracy", 1.0e-8)
4459 self.add_param("COLLIERCanOutput",False)
4460 self.add_param("COLLIERGlobalCache",-1)
4461 self.add_param("COLLIERUseCacheForPoles",False)
4462 self.add_param("COLLIERUseInternalStabilityTest",True)
4463
4464 - def read(self, finput):
4465 """Read the input file, this can be a path to a file,
4466 a file object, a str with the content of the file."""
4467
4468 if isinstance(finput, str):
4469 if "\n" in finput:
4470 finput = finput.split('\n')
4471 elif os.path.isfile(finput):
4472 finput = open(finput)
4473 else:
4474 raise Exception("No such file %s" % input)
4475
4476 previous_line= ''
4477 for line in finput:
4478 if previous_line.startswith('#'):
4479 name = previous_line[1:].split()[0]
4480 value = line.strip()
4481 if len(value) and value[0] not in ['#', '!']:
4482 self.__setitem__(name, value, change_userdefine=True)
4483 previous_line = line
4484
4485
4486 - def write(self, outputpath, template=None,commentdefault=False):
4487
4488 if not template:
4489 if not MADEVENT:
4490 template = pjoin(MG5DIR, 'Template', 'loop_material', 'StandAlone',
4491 'Cards', 'MadLoopParams.dat')
4492 else:
4493 template = pjoin(MEDIR, 'Cards', 'MadLoopParams_default.dat')
4494 fsock = open(template, 'r')
4495 template = fsock.readlines()
4496 fsock.close()
4497
4498 if isinstance(outputpath, str):
4499 output = open(outputpath, 'w')
4500 else:
4501 output = outputpath
4502
4503 def f77format(value):
4504 if isinstance(value, bool):
4505 if value:
4506 return '.true.'
4507 else:
4508 return '.false.'
4509 elif isinstance(value, int):
4510 return value
4511 elif isinstance(value, float):
4512 tmp ='%e' % value
4513 return tmp.replace('e','d')
4514 elif isinstance(value, str):
4515 return value
4516 else:
4517 raise Exception("Can not format input %s" % type(value))
4518
4519 name = ''
4520 done = set()
4521 for line in template:
4522 if name:
4523 done.add(name)
4524 if commentdefault and name.lower() not in self.user_set :
4525 output.write('!%s\n' % f77format(self[name]))
4526 else:
4527 output.write('%s\n' % f77format(self[name]))
4528 name=''
4529 continue
4530 elif line.startswith('#'):
4531 name = line[1:].split()[0]
4532 output.write(line)
4533