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