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