1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 from __future__ import division
17 from __future__ import absolute_import
18 import collections
19 import copy
20 import logging
21 import numbers
22 import os
23 import sys
24 import re
25 import math
26 import six
27 StringIO = six
28 from six.moves import range
29 if six.PY3:
30 import io
31 file = io.IOBase
32 import itertools
33 import time
34
35
36 pjoin = os.path.join
37
38 try:
39 import madgraph
40 except ImportError:
41 MADEVENT = True
42 from internal import MadGraph5Error, InvalidCmd
43 import internal.file_writers as file_writers
44 import internal.files as files
45 import internal.check_param_card as param_card_reader
46 import internal.misc as misc
47 MEDIR = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
48 MEDIR = os.path.split(MEDIR)[0]
49 else:
50 MADEVENT = False
51 import madgraph.various.misc as misc
52 import madgraph.iolibs.file_writers as file_writers
53 import madgraph.iolibs.files as files
54 import models.check_param_card as param_card_reader
55 from madgraph import MG5DIR, MadGraph5Error, InvalidCmd
56
57
58
59 logger = logging.getLogger('madevent.cards')
64
67 """ """
68
69 ordered_items = ['mgversion', 'mg5proccard', 'mgproccard', 'mgruncard',
70 'slha','initrwgt','mggenerationinfo', 'mgpythiacard', 'mgpgscard',
71 'mgdelphescard', 'mgdelphestrigger','mgshowercard',
72 'ma5card_parton','ma5card_hadron','run_settings']
73
74 capitalized_items = {
75 'mgversion': 'MGVersion',
76 'mg5proccard': 'MG5ProcCard',
77 'mgproccard': 'MGProcCard',
78 'mgruncard': 'MGRunCard',
79 'ma5card_parton' : 'MA5Card_parton',
80 'ma5card_hadron' : 'MA5Card_hadron',
81 'mggenerationinfo': 'MGGenerationInfo',
82 'mgpythiacard': 'MGPythiaCard',
83 'mgpgscard': 'MGPGSCard',
84 'mgdelphescard': 'MGDelphesCard',
85 'mgdelphestrigger': 'MGDelphesTrigger',
86 'mgshowercard': 'MGShowerCard' }
87
88 forbid_cdata = ['initrwgt']
89
91 """ """
92
93 if isinstance(banner_path, Banner):
94 dict.__init__(self, banner_path)
95 self.lhe_version = banner_path.lhe_version
96 return
97 else:
98 dict.__init__(self)
99
100
101 if MADEVENT:
102 self['mgversion'] = '#%s\n' % open(pjoin(MEDIR, 'MGMEVersion.txt')).read()
103 else:
104 info = misc.get_pkg_info()
105 self['mgversion'] = info['version']+'\n'
106
107 self.lhe_version = None
108
109
110 if banner_path:
111 self.read_banner(banner_path)
112
113
114
115
116 pat_begin=re.compile('<(?P<name>\w*)>')
117 pat_end=re.compile('</(?P<name>\w*)>')
118
119 tag_to_file={'slha':'param_card.dat',
120 'mgruncard':'run_card.dat',
121 'mgpythiacard':'pythia_card.dat',
122 'mgpgscard' : 'pgs_card.dat',
123 'mgdelphescard':'delphes_card.dat',
124 'mgdelphestrigger':'delphes_trigger.dat',
125 'mg5proccard':'proc_card_mg5.dat',
126 'mgproccard': 'proc_card.dat',
127 'init': '',
128 'mggenerationinfo':'',
129 'scalesfunctionalform':'',
130 'montecarlomasses':'',
131 'initrwgt':'',
132 'madspin':'madspin_card.dat',
133 'mgshowercard':'shower_card.dat',
134 'pythia8':'pythia8_card.dat',
135 'ma5card_parton':'madanalysis5_parton_card.dat',
136 'ma5card_hadron':'madanalysis5_hadron_card.dat',
137 'run_settings':''
138 }
139
141 """read a banner"""
142
143 if isinstance(input_path, str):
144 if input_path.find('\n') ==-1:
145 input_path = open(input_path)
146 else:
147 def split_iter(string):
148 return (x.groups(0)[0] for x in re.finditer(r"([^\n]*\n)", string, re.DOTALL))
149 input_path = split_iter(input_path)
150
151 text = ''
152 store = False
153 for line in input_path:
154 if self.pat_begin.search(line):
155 if self.pat_begin.search(line).group('name').lower() in self.tag_to_file:
156 tag = self.pat_begin.search(line).group('name').lower()
157 store = True
158 continue
159 if store and self.pat_end.search(line):
160 if tag == self.pat_end.search(line).group('name').lower():
161 self[tag] = text
162 text = ''
163 store = False
164 if store and not line.startswith(('<![CDATA[',']]>')):
165 if line.endswith('\n'):
166 text += line
167 else:
168 text += '%s%s' % (line, '\n')
169
170
171 if "</init>" in line:
172 break
173 elif "<event>" in line:
174 break
175
177 """allow auto-build for the run_card/param_card/... """
178 try:
179 return super(Banner, self).__getattribute__(attr)
180 except:
181 if attr not in ['run_card', 'param_card', 'slha', 'mgruncard', 'mg5proccard', 'mgshowercard', 'foanalyse']:
182 raise
183 return self.charge_card(attr)
184
185
186
188 """change the lhe version associate to the banner"""
189
190 version = float(version)
191 if version < 3:
192 version = 1
193 elif version > 3:
194 raise Exception("Not Supported version")
195 self.lhe_version = version
196
198 """return the cross-section of the file"""
199
200 if "init" not in self:
201 raise Exception
202
203 text = self["init"].split('\n')
204 cross = 0
205 error = 0
206 for line in text:
207 s = line.split()
208 if len(s)==4:
209 cross += float(s[0])
210 if witherror:
211 error += float(s[1])**2
212 if not witherror:
213 return cross
214 else:
215 return cross, math.sqrt(error)
216
217
219 """modify the init information with the associate scale"""
220
221 assert "init" in self
222
223 all_lines = self["init"].split('\n')
224 new_data = []
225 new_data.append(all_lines[0])
226 for i in range(1, len(all_lines)):
227 line = all_lines[i]
228 split = line.split()
229 if len(split) == 4:
230 xsec, xerr, xmax, pid = split
231 else:
232 new_data += all_lines[i:]
233 break
234 pid = int(pid)
235
236 line = " %+13.7e %+13.7e %+13.7e %i" % \
237 (ratio*float(xsec), ratio* float(xerr), ratio*float(xmax), pid)
238 new_data.append(line)
239 self['init'] = '\n'.join(new_data)
240
242 """return the pdg of each beam"""
243
244 assert "init" in self
245
246 all_lines = self["init"].split('\n')
247 pdg1,pdg2,_ = all_lines[0].split(None, 2)
248 return int(pdg1), int(pdg2)
249
251 """ Load the proc_card /param_card and run_card """
252
253 self.add(pjoin(medir,'Cards', 'param_card.dat'))
254 self.add(pjoin(medir,'Cards', 'run_card.dat'))
255 if os.path.exists(pjoin(medir, 'SubProcesses', 'procdef_mg5.dat')):
256 self.add(pjoin(medir,'SubProcesses', 'procdef_mg5.dat'))
257 self.add(pjoin(medir,'Cards', 'proc_card_mg5.dat'))
258 else:
259 self.add(pjoin(medir,'Cards', 'proc_card.dat'))
260
262 """Change the seed value in the banner"""
263
264 p = re.compile(r'''^\s*\d+\s*=\s*iseed''', re.M)
265 new_seed_str = " %s = iseed" % seed
266 self['mgruncard'] = p.sub(new_seed_str, self['mgruncard'])
267
269 """add info on MGGeneration"""
270
271 text = """
272 # Number of Events : %s
273 # Integrated weight (pb) : %s
274 """ % (nb_event, cross)
275 self['MGGenerationInfo'] = text
276
277
278
279
280 - def split(self, me_dir, proc_card=True):
281 """write the banner in the Cards directory.
282 proc_card argument is present to avoid the overwrite of proc_card
283 information"""
284
285 for tag, text in self.items():
286 if tag == 'mgversion':
287 continue
288 if not proc_card and tag in ['mg5proccard','mgproccard']:
289 continue
290 if not self.tag_to_file[tag]:
291 continue
292 ff = open(pjoin(me_dir, 'Cards', self.tag_to_file[tag]), 'w')
293 ff.write(text)
294 ff.close()
295
296
297
298
299
301 """special routine removing width/mass of particles not present in the model
302 This is usefull in case of loop model card, when we want to use the non
303 loop model."""
304
305 if not hasattr(self, 'param_card'):
306 self.charge_card('slha')
307
308 for tag in ['mass', 'decay']:
309 block = self.param_card.get(tag)
310 for data in block:
311 pid = data.lhacode[0]
312 if pid not in list(pid2label.keys()):
313 block.remove((pid,))
314
316 """get the lha_strategy: how the weight have to be handle by the shower"""
317
318 if not self["init"]:
319 raise Exception("No init block define")
320
321 data = self["init"].split('\n')[0].split()
322 if len(data) != 10:
323 misc.sprint(len(data), self['init'])
324 raise Exception("init block has a wrong format")
325 return int(float(data[-2]))
326
328 """set the lha_strategy: how the weight have to be handle by the shower"""
329
330 if not (-4 <= int(value) <= 4):
331 six.reraise(Exception, "wrong value for lha_strategy", value)
332 if not self["init"]:
333 raise Exception("No init block define")
334
335 all_lines = self["init"].split('\n')
336 data = all_lines[0].split()
337 if len(data) != 10:
338 misc.sprint(len(data), self['init'])
339 raise Exception("init block has a wrong format")
340 data[-2] = '%s' % value
341 all_lines[0] = ' '.join(data)
342 self['init'] = '\n'.join(all_lines)
343
344
346 """modify the init information with the associate cross-section"""
347 assert isinstance(cross, dict)
348
349 assert "init" in self
350
351 cross = dict(cross)
352 for key in cross.keys():
353 if isinstance(key, str) and key.isdigit() and int(key) not in cross:
354 cross[int(key)] = cross[key]
355
356
357 all_lines = self["init"].split('\n')
358 new_data = []
359 new_data.append(all_lines[0])
360 for i in range(1, len(all_lines)):
361 line = all_lines[i]
362 split = line.split()
363 if len(split) == 4:
364 xsec, xerr, xmax, pid = split
365 else:
366 new_data += all_lines[i:]
367 break
368 if int(pid) not in cross:
369 raise Exception
370 pid = int(pid)
371 if float(xsec):
372 ratio = cross[pid]/float(xsec)
373 else:
374 ratio = 0
375 line = " %+13.7e %+13.7e %+13.7e %i" % \
376 (float(cross[pid]), ratio* float(xerr), ratio*float(xmax), pid)
377 new_data.append(line)
378 self['init'] = '\n'.join(new_data)
379
380
381
382
383 - def write(self, output_path, close_tag=True, exclude=[]):
384 """write the banner"""
385
386 if isinstance(output_path, str):
387 ff = open(output_path, 'w')
388 else:
389 ff = output_path
390
391 if MADEVENT:
392 header = open(pjoin(MEDIR, 'Source', 'banner_header.txt')).read()
393 else:
394 header = open(pjoin(MG5DIR,'Template', 'LO', 'Source', 'banner_header.txt')).read()
395
396 if not self.lhe_version:
397 self.lhe_version = self.get('run_card', 'lhe_version', default=1.0)
398 if float(self.lhe_version) < 3:
399 self.lhe_version = 1.0
400 out = header % { 'version':float(self.lhe_version)}
401 try:
402 ff.write(out)
403 except:
404 ff.write(out.encode('utf-8'))
405
406 for tag in [t for t in self.ordered_items if t in list(self.keys())]+ \
407 [t for t in self.keys() if t not in self.ordered_items]:
408 if tag in ['init'] or tag in exclude:
409 continue
410 capitalized_tag = self.capitalized_items[tag] if tag in self.capitalized_items else tag
411 start_data, stop_data = '', ''
412 if capitalized_tag not in self.forbid_cdata and \
413 ('<' in self[tag] or '@' in self[tag]):
414 start_data = '\n<![CDATA['
415 stop_data = ']]>\n'
416 out = '<%(tag)s>%(start_data)s\n%(text)s\n%(stop_data)s</%(tag)s>\n' % \
417 {'tag':capitalized_tag, 'text':self[tag].strip(),
418 'start_data': start_data, 'stop_data':stop_data}
419 try:
420 ff.write(out)
421 except:
422 ff.write(out.encode('utf-8'))
423
424
425 if not '/header' in exclude:
426 out = '</header>\n'
427 try:
428 ff.write(out)
429 except:
430 ff.write(out.encode('utf-8'))
431
432 if 'init' in self and not 'init' in exclude:
433 text = self['init']
434 out = '<%(tag)s>\n%(text)s\n</%(tag)s>\n' % \
435 {'tag':'init', 'text':text.strip()}
436 try:
437 ff.write(out)
438 except:
439 ff.write(out.encode('utf-8'))
440
441 if close_tag:
442 out = '</LesHouchesEvents>\n'
443 try:
444 ff.write(out)
445 except:
446 ff.write(out.encode('utf-8'))
447 return ff
448
449
450
451
452
453 - def add(self, path, tag=None):
454 """Add the content of the file to the banner"""
455
456 if not tag:
457 card_name = os.path.basename(path)
458 if 'param_card' in card_name:
459 tag = 'slha'
460 elif 'run_card' in card_name:
461 tag = 'MGRunCard'
462 elif 'pythia_card' in card_name:
463 tag = 'MGPythiaCard'
464 elif 'pythia8_card' in card_name or 'pythia8.cmd' in card_name:
465 tag = 'MGPythiaCard'
466 elif 'pgs_card' in card_name:
467 tag = 'MGPGSCard'
468 elif 'delphes_card' in card_name:
469 tag = 'MGDelphesCard'
470 elif 'delphes_trigger' in card_name:
471 tag = 'MGDelphesTrigger'
472 elif 'proc_card_mg5' in card_name:
473 tag = 'MG5ProcCard'
474 elif 'proc_card' in card_name:
475 tag = 'MGProcCard'
476 elif 'procdef_mg5' in card_name:
477 tag = 'MGProcCard'
478 elif 'shower_card' in card_name:
479 tag = 'MGShowerCard'
480 elif 'madspin_card' in card_name:
481 tag = 'madspin'
482 elif 'FO_analyse_card' in card_name:
483 tag = 'foanalyse'
484 elif 'reweight_card' in card_name:
485 tag='reweight_card'
486 elif 'madanalysis5_parton_card' in card_name:
487 tag='MA5Card_parton'
488 elif 'madanalysis5_hadron_card' in card_name:
489 tag='MA5Card_hadron'
490 else:
491 raise Exception('Impossible to know the type of the card')
492
493 self.add_text(tag.lower(), open(path).read())
494
495 - def add_text(self, tag, text):
496 """Add the content of the file to the banner"""
497
498 if tag == 'param_card':
499 tag = 'slha'
500 elif tag == 'run_card':
501 tag = 'mgruncard'
502 elif tag == 'proc_card':
503 tag = 'mg5proccard'
504 elif tag == 'shower_card':
505 tag = 'mgshowercard'
506 elif tag == 'FO_analyse_card':
507 tag = 'foanalyse'
508
509 self[tag.lower()] = text
510
511
561
562
564 """return a specific """
565
566 if tag in ['param_card', 'param']:
567 tag = 'slha'
568 attr_tag = 'param_card'
569 elif tag in ['run_card', 'run']:
570 tag = 'mgruncard'
571 attr_tag = 'run_card'
572 elif tag == 'proc_card':
573 tag = 'mg5proccard'
574 attr_tag = 'proc_card'
575 elif tag == 'model':
576 tag = 'mg5proccard'
577 attr_tag = 'proc_card'
578 arg = ('model',)
579 elif tag == 'generate':
580 tag = 'mg5proccard'
581 attr_tag = 'proc_card'
582 arg = ('generate',)
583 elif tag == 'shower_card':
584 tag = 'mgshowercard'
585 attr_tag = 'shower_card'
586 assert tag in ['slha', 'mgruncard', 'mg5proccard', 'shower_card'], '%s not recognized' % tag
587
588 if not hasattr(self, attr_tag):
589 self.charge_card(attr_tag)
590
591 card = getattr(self, attr_tag)
592 if len(arg) == 0:
593 return card
594 elif len(arg) == 1:
595 if tag == 'mg5proccard':
596 try:
597 return card.get(arg[0])
598 except KeyError as error:
599 if 'default' in opt:
600 return opt['default']
601 else:
602 raise
603 try:
604 return card[arg[0]]
605 except KeyError:
606 if 'default' in opt:
607 return opt['default']
608 else:
609 raise
610 elif len(arg) == 2 and tag == 'slha':
611 try:
612 return card[arg[0]].get(arg[1:])
613 except KeyError:
614 if 'default' in opt:
615 return opt['default']
616 else:
617 raise
618 elif len(arg) == 0:
619 return card
620 else:
621 raise Exception("Unknow command")
622
623
624 get = get_detail
625
626 - def set(self, card, *args):
627 """modify one of the cards"""
628
629 if tag == 'param_card':
630 tag = 'slha'
631 attr_tag = 'param_card'
632 elif tag == 'run_card':
633 tag = 'mgruncard'
634 attr_tag = 'run_card'
635 elif tag == 'proc_card':
636 tag = 'mg5proccard'
637 attr_tag = 'proc_card'
638 elif tag == 'model':
639 tag = 'mg5proccard'
640 attr_tag = 'proc_card'
641 arg = ('model',)
642 elif tag == 'generate':
643 tag = 'mg5proccard'
644 attr_tag = 'proc_card'
645 arg = ('generate',)
646 elif tag == 'shower_card':
647 tag = 'mgshowercard'
648 attr_tag = 'shower_card'
649 assert tag in ['slha', 'mgruncard', 'mg5proccard', 'shower_card'], 'not recognized'
650
651 if not hasattr(self, attr_tag):
652 self.charge_card(attr_tag)
653
654 card = getattr(self, attr_tag)
655 if len(args) ==2:
656 if tag == 'mg5proccard':
657 card.info[args[0]] = args[-1]
658 else:
659 card[args[0]] = args[1]
660 else:
661 card[args[:-1]] = args[-1]
662
663
664 @misc.multiple_try()
666 """Add the banner to a file and change the associate seed in the banner"""
667
668 if seed is not None:
669 self.set("run_card", "iseed", seed)
670
671 if not out:
672 path_out = "%s.tmp" % path
673 else:
674 path_out = out
675
676 ff = self.write(path_out, close_tag=False,
677 exclude=['MGGenerationInfo', '/header', 'init'])
678 ff.write("## END BANNER##\n")
679 if self.lhe_version >= 3:
680
681 [ff.write(line) if not line.startswith("<generator name='MadGraph5_aMC@NLO'")
682 else ff.write("<generator name='MadGraph5_aMC@NLO' version='%s'>" % self['mgversion'][:-1])
683 for line in open(path)]
684 else:
685 [ff.write(line) for line in open(path)]
686 ff.write("</LesHouchesEvents>\n")
687 ff.close()
688 if out:
689 os.remove(path)
690 else:
691 files.mv(path_out, path)
692
693
694
695 -def split_banner(banner_path, me_dir, proc_card=True):
700
702 """as input we receive a gen_crossxhtml.AllResults object.
703 This define the current banner and load it
704 """
705
706 if not run:
707 try:
708 _run = results_object.current['run_name']
709 _tag = results_object.current['tag']
710 except Exception:
711 return Banner()
712 else:
713 _run = run
714 if not tag:
715 try:
716 _tag = results_object[run].tags[-1]
717 except Exception as error:
718 if os.path.exists( pjoin(results_object.path,'Events','%s_banner.txt' % (run))):
719 tag = None
720 else:
721 return Banner()
722 else:
723 _tag = tag
724
725
726 path = results_object.path
727 if tag:
728 banner_path = pjoin(path,'Events',run,'%s_%s_banner.txt' % (run, tag))
729 else:
730 banner_path = pjoin(results_object.path,'Events','%s_banner.txt' % (run))
731
732 if not os.path.exists(banner_path):
733 if level != "parton" and tag != _tag:
734 return recover_banner(results_object, level, _run, results_object[_run].tags[0])
735 elif level == 'parton':
736 paths = [pjoin(path,'Events',run, 'unweighted_events.lhe.gz'),
737 pjoin(path,'Events',run, 'unweighted_events.lhe'),
738 pjoin(path,'Events',run, 'events.lhe.gz'),
739 pjoin(path,'Events',run, 'events.lhe')]
740 for p in paths:
741 if os.path.exists(p):
742 if MADEVENT:
743 import internal.lhe_parser as lhe_parser
744 else:
745 import madgraph.various.lhe_parser as lhe_parser
746 lhe = lhe_parser.EventFile(p)
747 return Banner(lhe.banner)
748
749
750 return Banner()
751
752 banner = Banner(banner_path)
753
754
755
756 if level == 'pythia':
757 if 'mgpythiacard' in banner:
758 del banner['mgpythiacard']
759 if level in ['pythia','pgs','delphes']:
760 for tag in ['mgpgscard', 'mgdelphescard', 'mgdelphestrigger']:
761 if tag in banner:
762 del banner[tag]
763 return banner
764
767
769 """Basic Proccard object"""
770
771 history_header = \
772 '#************************************************************\n' + \
773 '#* MadGraph5_aMC@NLO *\n' + \
774 '#* *\n' + \
775 "#* * * *\n" + \
776 "#* * * * * *\n" + \
777 "#* * * * * 5 * * * * *\n" + \
778 "#* * * * * *\n" + \
779 "#* * * *\n" + \
780 "#* *\n" + \
781 "#* *\n" + \
782 "%(info_line)s" +\
783 "#* *\n" + \
784 "#* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \
785 "#* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
786 '#* *\n' + \
787 '#************************************************************\n' + \
788 '#* *\n' + \
789 '#* Command File for MadGraph5_aMC@NLO *\n' + \
790 '#* *\n' + \
791 '#* run as ./bin/mg5_aMC filename *\n' + \
792 '#* *\n' + \
793 '#************************************************************\n'
794
795
796
797
799 """ initialize a basic proc_card"""
800 self.info = {'model': 'sm', 'generate':None,
801 'full_model_line':'import model sm'}
802 list.__init__(self)
803 if init:
804 self.read(init)
805
806
807 - def read(self, init):
808 """read the proc_card and save the information"""
809
810 if isinstance(init, str):
811 init = open(init, 'r')
812
813 store_line = ''
814 for line in init:
815 line = line.rstrip()
816 if line.endswith('\\'):
817 store_line += line[:-1]
818 else:
819 tmp = store_line + line
820 self.append(tmp.strip())
821 store_line = ""
822 if store_line:
823 raise Exception("WRONG CARD FORMAT")
824
825
827 """move an element to the last history."""
828 for line in self[:]:
829 if line.startswith(cmd):
830 self.remove(line)
831 list.append(self, line)
832
834 """"add a line in the proc_card perform automatically cleaning"""
835
836 line = line.strip()
837 cmds = line.split()
838 if len(cmds) == 0:
839 return
840
841 list.append(self, line)
842
843
844 cmd = cmds[0]
845
846 if cmd == 'output':
847
848 self.clean(allow_for_removal = ['output'], keep_switch=True,
849 remove_bef_last='output')
850 elif cmd == 'generate':
851
852 self.clean(remove_bef_last='generate', keep_switch=True,
853 allow_for_removal= ['generate', 'add process', 'output'])
854 self.info['generate'] = ' '.join(cmds[1:])
855 elif cmd == 'add' and cmds[1] == 'process' and not self.info['generate']:
856 self.info['generate'] = ' '.join(cmds[2:])
857 elif cmd == 'import':
858 if len(cmds) < 2:
859 return
860 if cmds[1].startswith('model'):
861 self.info['full_model_line'] = line
862 self.clean(remove_bef_last='import', keep_switch=True,
863 allow_for_removal=['generate', 'add process', 'add model', 'output'])
864 if cmds[1] == 'model':
865 self.info['model'] = cmds[2]
866 else:
867 self.info['model'] = None
868 elif cmds[1] == 'proc_v4':
869
870 self[:] = []
871
872
873 - def clean(self, to_keep=['set','add','load'],
874 remove_bef_last=None,
875 to_remove=['open','display','launch', 'check','history'],
876 allow_for_removal=None,
877 keep_switch=False):
878 """Remove command in arguments from history.
879 All command before the last occurrence of 'remove_bef_last'
880 (including it) will be removed (but if another options tells the opposite).
881 'to_keep' is a set of line to always keep.
882 'to_remove' is a set of line to always remove (don't care about remove_bef_
883 status but keep_switch acts.).
884 if 'allow_for_removal' is define only the command in that list can be
885 remove of the history for older command that remove_bef_lb1. all parameter
886 present in to_remove are always remove even if they are not part of this
887 list.
888 keep_switch force to keep the statement remove_bef_??? which changes starts
889 the removal mode.
890 """
891
892
893 if __debug__ and allow_for_removal:
894 for arg in to_keep:
895 assert arg not in allow_for_removal
896
897
898 nline = -1
899 removal = False
900
901 while nline > -len(self):
902 switch = False
903
904
905 if not removal and remove_bef_last:
906 if self[nline].startswith(remove_bef_last):
907 removal = True
908 switch = True
909
910
911 if switch and keep_switch:
912 nline -= 1
913 continue
914
915
916 if any([self[nline].startswith(arg) for arg in to_remove]):
917 self.pop(nline)
918 continue
919
920
921 if removal:
922 if allow_for_removal:
923
924 if any([self[nline].startswith(arg)
925 for arg in allow_for_removal]):
926 self.pop(nline)
927 continue
928 elif not any([self[nline].startswith(arg) for arg in to_keep]):
929
930 self.pop(nline)
931 continue
932
933
934 nline -= 1
935
936 - def get(self, tag, default=None):
937 if isinstance(tag, int):
938 list.__getattr__(self, tag)
939 elif tag == 'info' or tag == "__setstate__":
940 return default
941 elif tag == "multiparticles":
942 out = []
943 for line in self:
944 if line.startswith('define'):
945 try:
946 name, content = line[7:].split('=',1)
947 except ValueError:
948 name, content = line[7:].split(None,1)
949 out.append((name, content))
950 return out
951 else:
952 return self.info[tag]
953
955 """write the proc_card to a given path"""
956
957 fsock = open(path, 'w')
958 fsock.write(self.history_header)
959 for line in self:
960 while len(line) > 70:
961 sub, line = line[:70]+"\\" , line[70:]
962 fsock.write(sub+"\n")
963 else:
964 fsock.write(line+"\n")
965
967
969 """ a class for storing/dealing with input file.
970 """
971
972 - def __init__(self, finput=None, **opt):
973 """initialize a new instance. input can be an instance of MadLoopParam,
974 a file, a path to a file, or simply Nothing"""
975
976 if isinstance(finput, self.__class__):
977 dict.__init__(self, finput)
978 for key in finput.__dict__:
979 setattr(self, key, copy.copy(getattr(finput, key)) )
980 for key,value in finput.items():
981 dict.__setitem__(self, key.lower(), value)
982 return
983 else:
984 dict.__init__(self)
985
986
987 self.user_set = set()
988 self.auto_set = set()
989 self.system_only = set()
990 self.lower_to_case = {}
991 self.list_parameter = {}
992 self.dict_parameter = {}
993 self.comments = {}
994
995 self.allowed_value = {}
996
997 self.default_setup()
998
999
1000
1001 if isinstance(finput, (file, str, StringIO.StringIO)):
1002 self.read(finput, **opt)
1003
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
1769 newone = type(self)(dict(self))
1770 newone.__dict__.update(self.__dict__)
1771 return newone
1772
1773 - def add_param(self, name, value, hidden=False, always_write_to_card=True,
1774 comment=None):
1775 """ add a parameter to the card. value is the default value and
1776 defines the type (int/float/bool/str) of the input.
1777 The option 'hidden' decides whether the parameter should be visible to the user.
1778 The option 'always_write_to_card' decides whether it should
1779 always be printed or only when it is system_set or user_set.
1780 The option 'comment' can be used to specify a comment to write above
1781 hidden parameters.
1782 """
1783 super(PY8Card, self).add_param(name, value, comment=comment)
1784 name = name.lower()
1785 if hidden:
1786 self.hidden_param.append(name)
1787 if always_write_to_card:
1788 self.hidden_params_to_always_write.add(name)
1789 else:
1790 if always_write_to_card:
1791 self.visible_params_to_always_write.add(name)
1792 if not comment is None:
1793 if not isinstance(comment, str):
1794 raise MadGraph5Error("Option 'comment' must be a string, not"+\
1795 " '%s'."%str(comment))
1796
1798 """Add a subrun to this PY8 Card."""
1799 assert(isinstance(py8_subrun,PY8SubRun))
1800 if py8_subrun['Main:subrun']==-1:
1801 raise MadGraph5Error("Make sure to correctly set the subrun ID"+\
1802 " 'Main:subrun' *before* adding it to the PY8 Card.")
1803 if py8_subrun['Main:subrun'] in self.subruns:
1804 raise MadGraph5Error("A subrun with ID '%s'"%py8_subrun['Main:subrun']+\
1805 " is already present in this PY8 card. Remove it first, or "+\
1806 " access it directly.")
1807 self.subruns[py8_subrun['Main:subrun']] = py8_subrun
1808 if not 'LHEFInputs:nSubruns' in self.user_set:
1809 self['LHEFInputs:nSubruns'] = max(self.subruns.keys())
1810
1811 - def userSet(self, name, value, **opts):
1812 """Set an attribute of this card, following a user_request"""
1813 self.__setitem__(name, value, change_userdefine=True, **opts)
1814 if name.lower() in self.system_set:
1815 self.system_set.remove(name.lower())
1816
1818 """ Forbid the writeout of a specific parameter of this card when the
1819 "write" function will be invoked."""
1820 self.params_to_never_write.add(name.lower())
1821
1823 """Set an attribute of this card, independently of a specific user
1824 request and only if not already user_set."""
1825 try:
1826 force = opts.pop('force')
1827 except KeyError:
1828 force = False
1829 if force or name.lower() not in self.user_set:
1830 self.__setitem__(name, value, change_userdefine=False, **opts)
1831 self.system_set.add(name.lower())
1832
1834 """ Sets a card attribute, but only if it is absent or not already
1835 user_set."""
1836 try:
1837 force = opts.pop('force')
1838 except KeyError:
1839 force = False
1840 if name.lower() not in self or (force or name.lower() not in self.user_set):
1841 self.__setitem__(name, value, change_userdefine=False, **opts)
1842 self.system_set.add(name.lower())
1843
1846
1847 @staticmethod
1898
1899
1900 - def write(self, output_file, template, read_subrun=False,
1901 print_only_visible=False, direct_pythia_input=False, add_missing=True):
1902 """ Write the card to output_file using a specific template.
1903 > 'print_only_visible' specifies whether or not the hidden parameters
1904 should be written out if they are in the hidden_params_to_always_write
1905 list and system_set.
1906 > If 'direct_pythia_input' is true, then visible parameters which are not
1907 in the self.visible_params_to_always_write list and are not user_set
1908 or system_set are commented.
1909 > If 'add_missing' is False then parameters that should be written_out but are absent
1910 from the template will not be written out."""
1911
1912
1913 visible_param = [p for p in self if p.lower() not in self.hidden_param
1914 or p.lower() in self.user_set]
1915
1916 visible_param = [p for p in visible_param if p.lower() not in self.params_to_never_write]
1917
1918
1919 if print_only_visible:
1920 hidden_output_param = []
1921 else:
1922 hidden_output_param = [p for p in self if p.lower() in self.hidden_param and
1923 not p.lower() in self.user_set and
1924 (p.lower() in self.hidden_params_to_always_write or
1925 p.lower() in self.system_set)]
1926
1927 hidden_output_param = [p for p in hidden_output_param if p not in self.params_to_never_write]
1928
1929 if print_only_visible:
1930 subruns = []
1931 else:
1932 if not read_subrun:
1933 subruns = sorted(self.subruns.keys())
1934
1935
1936
1937 subruns_to_write = {}
1938
1939
1940
1941 def group_params(params):
1942 if len(params)==0:
1943 return []
1944 groups = {}
1945 for p in params:
1946 try:
1947 groups[':'.join(p.split(':')[:-1])].append(p)
1948 except KeyError:
1949 groups[':'.join(p.split(':')[:-1])] = [p,]
1950 res = sum(list(groups.values()),[])
1951
1952 if 'Main:subrun' in res:
1953 res.insert(0,res.pop(res.index('Main:subrun')))
1954
1955 if 'LHEFInputs:nSubruns' in res:
1956 res.append(res.pop(res.index('LHEFInputs:nSubruns')))
1957 return res
1958
1959 visible_param = group_params(visible_param)
1960 hidden_output_param = group_params(hidden_output_param)
1961
1962
1963
1964 output = StringIO.StringIO()
1965
1966
1967 if isinstance(template, str):
1968 if os.path.isfile(template):
1969 tmpl = open(template, 'r')
1970 elif '\n' in template:
1971 tmpl = StringIO.StringIO(template)
1972 else:
1973 raise Exception("File input '%s' not found." % file_input)
1974 elif template is None:
1975
1976 tmpl = StringIO.StringIO()
1977 elif isinstance(template, (StringIO.StringIO, file)):
1978 tmpl = template
1979 else:
1980 raise MadGraph5Error("Incorrect type for argument 'template': %s"%
1981 template.__class__.__name__)
1982
1983
1984 last_pos = tmpl.tell()
1985 line = tmpl.readline()
1986 started_subrun_reading = False
1987 while line!='':
1988
1989 if line.strip().startswith('!') or \
1990 line.strip().startswith('\n') or\
1991 line.strip() == '':
1992 output.write(line)
1993
1994 last_pos = tmpl.tell()
1995 line = tmpl.readline()
1996 continue
1997
1998 try:
1999 param_entry, value_entry = line.split('=')
2000 param = param_entry.strip()
2001 value = value_entry.strip()
2002 except ValueError:
2003 line = line.replace('\n','')
2004 raise MadGraph5Error("Could not read line '%s' of Pythia8 card."%\
2005 line)
2006
2007 if param=='Main:subrun':
2008 if read_subrun:
2009 if not started_subrun_reading:
2010
2011 started_subrun_reading = True
2012 else:
2013
2014 tmpl.seek(last_pos)
2015 break
2016 else:
2017
2018 tmpl.seek(last_pos)
2019 subruns_to_write[int(value)] = StringIO.StringIO()
2020 if int(value) in subruns:
2021 self.subruns[int(value)].write(subruns_to_write[int(value)],
2022 tmpl,read_subrun=True)
2023
2024 subruns.pop(subruns.index(int(value)))
2025 else:
2026
2027 DummySubrun=PY8SubRun()
2028
2029 DummySubrun.clear()
2030 DummySubrun.write(subruns_to_write[int(value)],
2031 tmpl, read_subrun=True,
2032 print_only_visible=print_only_visible,
2033 direct_pythia_input=direct_pythia_input)
2034
2035 logger.info('Adding new unknown subrun with ID %d.'%
2036 int(value))
2037
2038 last_pos = tmpl.tell()
2039 line = tmpl.readline()
2040 continue
2041
2042
2043 if param in visible_param:
2044 new_value = PY8Card.pythia8_formatting(self[param])
2045 visible_param.pop(visible_param.index(param))
2046 elif param in hidden_output_param:
2047 new_value = PY8Card.pythia8_formatting(self[param])
2048 hidden_output_param.pop(hidden_output_param.index(param))
2049 else:
2050
2051 if param.lower() not in self.params_to_never_write:
2052 output.write(line)
2053 else:
2054 output.write('! The following parameter was forced to be commented out by MG5aMC.\n')
2055 output.write('! %s'%line)
2056
2057 last_pos = tmpl.tell()
2058 line = tmpl.readline()
2059 continue
2060
2061
2062
2063
2064
2065 if ((not direct_pythia_input) or
2066 (param.lower() in self.visible_params_to_always_write) or
2067 (param.lower() in self.user_set) or
2068 (param.lower() in self.system_set)):
2069 template = '%s=%s'
2070 else:
2071
2072
2073
2074 template = '!%s=%s'
2075
2076 output.write(template%(param_entry,
2077 value_entry.replace(value,new_value)))
2078
2079
2080 last_pos = tmpl.tell()
2081 line = tmpl.readline()
2082
2083
2084 if not add_missing:
2085 visible_param = []
2086 hidden_output_param = []
2087
2088
2089 if len(visible_param)>0 and not template is None:
2090 output.write(
2091 """!
2092 ! Additional general parameters%s.
2093 !
2094 """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else ''))
2095 for param in visible_param:
2096 value = PY8Card.pythia8_formatting(self[param])
2097 output.write('%s=%s\n'%(param,value))
2098 if template is None:
2099 if param=='Main:subrun':
2100 output.write(
2101 """!
2102 ! Definition of subrun %d
2103 !
2104 """%self['Main:subrun'])
2105 elif param.lower() not in self.hidden_param:
2106 logger.debug('Adding parameter %s (missing in the template) to current '+\
2107 'pythia8 card (with value %s)',param, value)
2108
2109 if len(hidden_output_param)>0 and not template is None:
2110 output.write(
2111 """!
2112 ! Additional technical parameters%s set by MG5_aMC.
2113 !
2114 """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else ''))
2115 for param in hidden_output_param:
2116 if param.lower() in self.comments:
2117 comment = '\n'.join('! %s'%c for c in
2118 self.comments[param.lower()].split('\n'))
2119 output.write(comment+'\n')
2120 output.write('%s=%s\n'%(param,PY8Card.pythia8_formatting(self[param])))
2121
2122
2123
2124 if read_subrun:
2125 output_file.write(output.getvalue())
2126 return
2127
2128
2129 for subrunID in subruns:
2130 new_subrun = StringIO.StringIO()
2131 self.subruns[subrunID].write(new_subrun,None,read_subrun=True)
2132 subruns_to_write[subrunID] = new_subrun
2133
2134
2135 for subrunID in sorted(subruns_to_write):
2136 output.write(subruns_to_write[subrunID].getvalue())
2137
2138
2139
2140 if 'LHEFInputs:nSubruns'.lower() not in self.user_set and \
2141 len(subruns_to_write)>0 and 'LHEFInputs:nSubruns' in self\
2142 and self['LHEFInputs:nSubruns']<max(subruns_to_write.keys()):
2143 logger.info("Updating PY8 parameter 'LHEFInputs:nSubruns' to "+
2144 "%d so as to cover all defined subruns."%max(subruns_to_write.keys()))
2145 self['LHEFInputs:nSubruns'] = max(subruns_to_write.keys())
2146 output = StringIO.StringIO()
2147 self.write(output,template,print_only_visible=print_only_visible)
2148
2149
2150 if isinstance(output_file, str):
2151 out = open(output_file,'w')
2152 out.write(output.getvalue())
2153 out.close()
2154 else:
2155 output_file.write(output.getvalue())
2156
2157 - def read(self, file_input, read_subrun=False, setter='default'):
2158 """Read the input file, this can be a path to a file,
2159 a file object, a str with the content of the file.
2160 The setter option choses the authority that sets potential
2161 modified/new parameters. It can be either:
2162 'default' or 'user' or 'system'"""
2163 if isinstance(file_input, str):
2164 if "\n" in file_input:
2165 finput = StringIO.StringIO(file_input)
2166 elif os.path.isfile(file_input):
2167 finput = open(file_input)
2168 else:
2169 raise Exception("File input '%s' not found." % file_input)
2170 elif isinstance(file_input, (StringIO.StringIO, file)):
2171 finput = file_input
2172 else:
2173 raise MadGraph5Error("Incorrect type for argument 'file_input': %s"%
2174 file_input.__class__.__name__)
2175
2176
2177 last_pos = finput.tell()
2178 line = finput.readline()
2179 started_subrun_reading = False
2180 while line!='':
2181
2182 if line.strip().startswith('!') or line.strip()=='':
2183
2184 last_pos = finput.tell()
2185 line = finput.readline()
2186 continue
2187
2188 try:
2189 param, value = line.split('=',1)
2190 param = param.strip()
2191 value = value.strip()
2192 except ValueError:
2193 line = line.replace('\n','')
2194 raise MadGraph5Error("Could not read line '%s' of Pythia8 card."%\
2195 line)
2196 if '!' in value:
2197 value,_ = value.split('!',1)
2198
2199
2200 if param=='Main:subrun':
2201 if read_subrun:
2202 if not started_subrun_reading:
2203
2204 started_subrun_reading = True
2205 else:
2206
2207 finput.seek(last_pos)
2208 return
2209 else:
2210
2211 finput.seek(last_pos)
2212 if int(value) in self.subruns:
2213 self.subruns[int(value)].read(finput,read_subrun=True,
2214 setter=setter)
2215 else:
2216
2217 NewSubrun=PY8SubRun()
2218 NewSubrun.read(finput,read_subrun=True, setter=setter)
2219 self.add_subrun(NewSubrun)
2220
2221
2222 last_pos = finput.tell()
2223 line = finput.readline()
2224 continue
2225
2226
2227
2228
2229
2230 if setter == 'user':
2231 self.userSet(param,value)
2232 elif setter == 'system':
2233 self.systemSet(param,value)
2234 else:
2235 self.defaultSet(param,value)
2236
2237
2238 last_pos = finput.tell()
2239 line = finput.readline()
2240
2242 """ Class to characterize a specific PY8 card subrun section. """
2243
2245 """ Overloading of the homonym function called in the __init__ of PY8Card.
2246 The initialization of the self.subruns attribute should of course not
2247 be performed in PY8SubRun."""
2248 pass
2249
2251 """ Initialize a subrun """
2252
2253
2254 subrunID = -1
2255 if 'subrun_id' in opts:
2256 subrunID = opts.pop('subrun_id')
2257
2258 super(PY8SubRun, self).__init__(*args, **opts)
2259 self['Main:subrun']=subrunID
2260
2262 """Sets up the list of available PY8SubRun parameters."""
2263
2264
2265 super(PY8SubRun, self).default_setup()
2266
2267 self.hidden_param = [k.lower() for k in self.keys()]
2268 self.hidden_params_to_always_write = set()
2269 self.visible_params_to_always_write = set()
2270
2271
2272 self.add_param("Main:subrun", -1)
2273 self.add_param("Beams:LHEF", "events.lhe.gz")
2274
2275
2276
2277 runblock = collections.namedtuple('block', ('name', 'fields', 'template_on', 'template_off'))
2279
2280 filename = 'run_card'
2281 LO = True
2282 blocks = []
2283
2284 - def __new__(cls, finput=None, **opt):
2285 if cls is RunCard:
2286 if not finput:
2287 target_class = RunCardLO
2288 elif isinstance(finput, cls):
2289 target_class = finput.__class__
2290 elif isinstance(finput, str):
2291 if '\n' not in finput:
2292 finput = open(finput).read()
2293 if 'req_acc_FO' in finput:
2294 target_class = RunCardNLO
2295 else:
2296 target_class = RunCardLO
2297 else:
2298 return None
2299 return super(RunCard, cls).__new__(target_class, finput, **opt)
2300 else:
2301 return super(RunCard, cls).__new__(cls, finput, **opt)
2302
2304
2305
2306
2307
2308 self.hidden_param = []
2309
2310 self.includepath = collections.defaultdict(list)
2311
2312 self.fortran_name = {}
2313
2314 self.legacy_parameter = {}
2315
2316
2317
2318
2319
2320 self.cuts_parameter = {}
2321
2322 self.system_default = {}
2323
2324 self.display_block = []
2325 self.cut_class = {}
2326 self.warned=False
2327
2328
2329 super(RunCard, self).__init__(*args, **opts)
2330
2331 - def add_param(self, name, value, fortran_name=None, include=True,
2332 hidden=False, legacy=False, cut=False, system=False, sys_default=None,
2333 **opts):
2334 """ add a parameter to the card. value is the default value and
2335 defines the type (int/float/bool/str) of the input.
2336 fortran_name defines what is the associate name in the f77 code
2337 include defines if we have to put the value in the include file
2338 hidden defines if the parameter is expected to be define by the user.
2339 legacy:Parameter which is not used anymore (raise a warning if not default)
2340 cut: defines the list of cut parameter to allow to set them all to off.
2341 sys_default: default used if the parameter is not in the card
2342
2343 options of **opts:
2344 - allowed: list of valid options. '*' means anything else should be allowed.
2345 empty list means anything possible as well.
2346 - comment: add comment for writing/help
2347 - typelist: type of the list if default is empty
2348 """
2349
2350 super(RunCard, self).add_param(name, value, system=system,**opts)
2351 name = name.lower()
2352 if fortran_name:
2353 self.fortran_name[name] = fortran_name
2354 if legacy:
2355 self.legacy_parameter[name] = value
2356 include = False
2357 self.includepath[include].append(name)
2358 if hidden or system:
2359 self.hidden_param.append(name)
2360 if cut:
2361 self.cuts_parameter[name] = cut
2362 if sys_default is not None:
2363 self.system_default[name] = sys_default
2364
2365
2366
2367 - def read(self, finput, consistency=True):
2368 """Read the input file, this can be a path to a file,
2369 a file object, a str with the content of the file."""
2370
2371 if isinstance(finput, str):
2372 if "\n" in finput:
2373 finput = finput.split('\n')
2374 elif os.path.isfile(finput):
2375 finput = open(finput)
2376 else:
2377 raise Exception("No such file %s" % finput)
2378
2379 for line in finput:
2380 line = line.split('#')[0]
2381 line = line.split('!')[0]
2382 line = line.rsplit('=',1)
2383 if len(line) != 2:
2384 continue
2385 value, name = line
2386 name = name.lower().strip()
2387 if name not in self and ('min' in name or 'max' in name):
2388
2389 self.add_param(name, float(value), hidden=True, cut=True)
2390 else:
2391 self.set( name, value, user=True)
2392
2393 if consistency:
2394 try:
2395 self.check_validity()
2396 except InvalidRunCard as error:
2397 if consistency == 'warning':
2398 logger.warning(str(error))
2399 else:
2400 raise
2401
2403 template_options = tmp
2404 default = template_options['default']
2405 if line.startswith('#IF('):
2406 cond = line[4:line.find(')')]
2407 if template_options.get(cond, default):
2408 return True
2409 else:
2410 return False
2411 elif line.strip().startswith('%'):
2412 parameter = line[line.find('(')+1:line.find(')')]
2413
2414 try:
2415 cond = self.cuts_parameter[parameter]
2416 except KeyError:
2417 return True
2418
2419
2420 if template_options.get(cond, default) or cond is True:
2421 return True
2422 else:
2423 return False
2424 else:
2425 return True
2426
2427
2428 - def write(self, output_file, template=None, python_template=False,
2429 write_hidden=False, template_options=None):
2430 """Write the run_card in output_file according to template
2431 (a path to a valid run_card)"""
2432
2433 to_write = set(self.user_set)
2434 written = set()
2435 if not template:
2436 raise Exception
2437 if not template_options:
2438 template_options = collections.defaultdict(str)
2439
2440
2441 write_block= []
2442 for b in self.blocks:
2443 name = b.name
2444
2445 if name not in self.display_block and \
2446 not any(f in self.user_set for f in b.fields):
2447 continue
2448 write_block.append(b.name)
2449
2450
2451 if python_template:
2452 text = open(template,'r').read()
2453 text = text.split('\n')
2454
2455 text = [l if not l.startswith('#IF') else l[l.find(')# ')+2:]
2456 for l in text if self.valid_line(l, template_options)]
2457 text ='\n'.join(text)
2458
2459 if python_template and not to_write:
2460 import string
2461 if self.blocks:
2462 text = string.Template(text)
2463 mapping = {}
2464 for b in self.blocks:
2465 if b.name in write_block:
2466 mapping[b.name] = b.template_on
2467 else:
2468 mapping[b.name] = b.template_off
2469 text = text.substitute(mapping)
2470
2471 if not self.list_parameter:
2472 text = text % self
2473 else:
2474 data = dict((key.lower(),value) for key, value in self.items())
2475 for name in self.list_parameter:
2476 if self.list_parameter[name] != str:
2477 data[name] = ', '.join(str(v) for v in data[name])
2478 else:
2479 data[name] = "['%s']" % "', '".join(str(v) for v in data[name])
2480 text = text % data
2481 else:
2482 text = ""
2483 for line in open(template,'r'):
2484 nline = line.split('#')[0]
2485 nline = nline.split('!')[0]
2486 comment = line[len(nline):]
2487 nline = nline.split('=')
2488 if python_template and nline[0].startswith('$'):
2489 block_name = nline[0][1:].strip()
2490 this_group = [b for b in self.blocks if b.name == block_name]
2491 if not this_group:
2492 logger.debug("block %s not defined", block_name)
2493 continue
2494 else:
2495 this_group = this_group[0]
2496 if block_name in write_block:
2497 text += this_group.template_on % self
2498 for name in this_group.fields:
2499 written.add(name)
2500 if name in to_write:
2501 to_write.remove(name)
2502 else:
2503 text += this_group.template_off % self
2504
2505 elif len(nline) != 2:
2506 text += line
2507 elif nline[1].strip() in self:
2508
2509 name = nline[1].strip().lower()
2510 value = self[name]
2511 if name in self.list_parameter:
2512 if self.list_parameter[name] != str:
2513 value = ', '.join([str(v) for v in value])
2514 else:
2515 value = "['%s']" % "', '".join(str(v) for v in value)
2516 if python_template:
2517 text += line % {nline[1].strip():value, name:value}
2518 written.add(name)
2519 else:
2520 if not comment or comment[-1]!='\n':
2521 endline = '\n'
2522 else:
2523 endline = ''
2524 text += ' %s\t= %s %s%s' % (value, name, comment, endline)
2525 written.add(name)
2526
2527 if name in to_write:
2528 to_write.remove(name)
2529 else:
2530 logger.info('Adding missing parameter %s to current %s (with default value)',
2531 (name, self.filename))
2532 written.add(name)
2533 text += line
2534
2535 for b in self.blocks:
2536 if b.name not in write_block:
2537 continue
2538
2539 if all(f in written for f in b.fields):
2540 continue
2541
2542 to_add = ['']
2543 for line in b.template_on.split('\n'):
2544 nline = line.split('#')[0]
2545 nline = nline.split('!')[0]
2546 nline = nline.split('=')
2547 if len(nline) != 2:
2548 to_add.append(line)
2549 elif nline[1].strip() in self:
2550 name = nline[1].strip().lower()
2551 value = self[name]
2552 if name in self.list_parameter:
2553 value = ', '.join([str(v) for v in value])
2554 if name in written:
2555 continue
2556 else:
2557 to_add.append(line % {nline[1].strip():value, name:value})
2558 written.add(name)
2559
2560 if name in to_write:
2561 to_write.remove(name)
2562 else:
2563 raise Exception
2564
2565 if b.template_off and b.template_off in text:
2566 text = text.replace(b.template_off, '\n'.join(to_add))
2567 else:
2568 text += '\n'.join(to_add)
2569
2570 if to_write or write_hidden:
2571 text+="""#*********************************************************************
2572 # Additional hidden parameters
2573 #*********************************************************************
2574 """
2575 if write_hidden:
2576
2577
2578
2579 if python_template:
2580 written = written.union(set(re.findall('\%\((\w*)\)s', open(template,'r').read(), re.M)))
2581 to_write = to_write.union(set(self.hidden_param))
2582 to_write = to_write.difference(written)
2583
2584 for key in to_write:
2585 if key in self.system_only:
2586 continue
2587
2588 comment = self.comments.get(key,'hidden_parameter').replace('\n','\n#')
2589 text += ' %s\t= %s # %s\n' % (self[key], key, comment)
2590
2591 if isinstance(output_file, str):
2592 fsock = open(output_file,'w')
2593 fsock.write(text)
2594 fsock.close()
2595 else:
2596 output_file.write(text)
2597
2598
2599 - def get_default(self, name, default=None, log_level=None):
2628
2629
2630 @staticmethod
2679
2680
2681
2683 """check that parameter missing in the card are set to the expected value"""
2684
2685 for name, value in self.system_default.items():
2686 self.set(name, value, changeifuserset=False)
2687
2688
2689 for name in self.includepath[False]:
2690 to_bypass = self.hidden_param + list(self.legacy_parameter.keys())
2691 if name not in to_bypass:
2692 self.get_default(name, log_level=log_level)
2693
2694 for name in self.legacy_parameter:
2695 if self[name] != self.legacy_parameter[name]:
2696 logger.warning("The parameter %s is not supported anymore this parameter will be ignored." % name)
2697
2698 default_include_file = 'run_card.inc'
2699
2701 """update hidden system only parameter for the correct writtin in the
2702 include"""
2703 return
2704
2706 """Write the various include file in output_dir.
2707 The entry True of self.includepath will be written in run_card.inc
2708 The entry False will not be written anywhere"""
2709
2710
2711 self.check_validity()
2712
2713
2714 self.update_system_parameter_for_include()
2715
2716 for incname in self.includepath:
2717 if incname is True:
2718 pathinc = self.default_include_file
2719 elif incname is False:
2720 continue
2721 else:
2722 pathinc = incname
2723
2724 fsock = file_writers.FortranWriter(pjoin(output_dir,pathinc))
2725 for key in self.includepath[incname]:
2726
2727 if key in self.fortran_name:
2728 fortran_name = self.fortran_name[key]
2729 else:
2730 fortran_name = key
2731
2732
2733 value = self.get_default(key)
2734
2735
2736 if isinstance(value, list):
2737
2738
2739
2740 targettype = self.list_parameter[key]
2741 if targettype is bool:
2742 pass
2743 elif targettype is int:
2744 line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(len(value)))
2745 fsock.writelines(line)
2746 elif targettype is float:
2747 line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(float(len(value))))
2748 fsock.writelines(line)
2749
2750 for i,v in enumerate(value):
2751 line = '%s(%s) = %s \n' % (fortran_name, i+1, self.f77_formatting(v))
2752 fsock.writelines(line)
2753 elif isinstance(value, dict):
2754 for fortran_name, onevalue in value.items():
2755 line = '%s = %s \n' % (fortran_name, self.f77_formatting(onevalue))
2756 fsock.writelines(line)
2757 elif isinstance(incname,str) and 'compile' in incname:
2758 line = '%s = %s \n' % (fortran_name, value)
2759 fsock.write(line)
2760 else:
2761 line = '%s = %s \n' % (fortran_name, self.f77_formatting(value))
2762 fsock.writelines(line)
2763 fsock.close()
2764
2765 @staticmethod
2767 """return the particle colliding pdg code"""
2768 if lpp in (1,2, -1,-2):
2769 return math.copysign(2212, lpp)
2770 elif lpp in (3,-3):
2771 return math.copysign(11, lpp)
2772 elif lpp == 0:
2773
2774 return 0
2775 else:
2776 return lpp
2777
2792
2794 if pdf == "lhapdf":
2795 lhaid = self["lhaid"]
2796 if isinstance(lhaid, list):
2797 return lhaid[0]
2798 else:
2799 return lhaid
2800 else:
2801 return {'none': 0,
2802 'cteq6_m':10000,'cteq6_l':10041,'cteq6l1':10042,
2803 'nn23lo':246800,'nn23lo1':247000,'nn23nlo':244800
2804 }[pdf]
2805
2808
2810 """remove all the cut"""
2811
2812 for name in self.cuts_parameter:
2813 targettype = type(self[name])
2814 if targettype == bool:
2815 self[name] = False
2816 if targettype == dict:
2817 self[name] = '{}'
2818 elif 'min' in name:
2819 self[name] = 0
2820 elif 'max' in name:
2821 self[name] = -1
2822 elif 'eta' in name:
2823 self[name] = -1
2824 else:
2825 self[name] = 0
2826
2828 """an object to handle in a nice way the run_card information"""
2829
2830 blocks = [
2831
2832 runblock(name='ion_pdf', fields=('nb_neutron1', 'nb_neutron2','nb_proton1','nb_proton2','mass_ion1', 'mass_ion2'),
2833 template_on=\
2834 """#*********************************************************************
2835 # Heavy ion PDF / rescaling of PDF *
2836 #*********************************************************************
2837 %(nb_proton1)s = nb_proton1 # number of proton for the first beam
2838 %(nb_neutron1)s = nb_neutron1 # number of neutron for the first beam
2839 %(mass_ion1)s = mass_ion1 # mass of the heavy ion (first beam)
2840 # Note that seting differently the two beams only work if you use
2841 # group_subprocess=False when generating your matrix-element
2842 %(nb_proton2)s = nb_proton2 # number of proton for the second beam
2843 %(nb_neutron2)s = nb_neutron2 # number of neutron for the second beam
2844 %(mass_ion2)s = mass_ion2 # mass of the heavy ion (second beam)
2845 """,
2846 template_off='# To see heavy ion options: type "update ion_pdf"'),
2847
2848
2849
2850 runblock(name='beam_pol', fields=('polbeam1','polbeam2'),
2851 template_on=\
2852 """#*********************************************************************
2853 # Beam polarization from -100 (left-handed) to 100 (right-handed) *
2854 #*********************************************************************
2855 %(polbeam1)s = polbeam1 ! beam polarization for beam 1
2856 %(polbeam2)s = polbeam2 ! beam polarization for beam 2
2857 """,
2858 template_off='# To see polarised beam options: type "update beam_pol"'),
2859
2860
2861 runblock(name='syscalc', fields=('sys_scalefact', 'sys_alpsfact','sys_matchscale','sys_pdf'),
2862 template_on=\
2863 """#**************************************
2864 # Parameter below of the systematics study
2865 # will be used by SysCalc (if installed)
2866 #**************************************
2867 #
2868 %(sys_scalefact)s = sys_scalefact # factorization/renormalization scale factor
2869 %(sys_alpsfact)s = sys_alpsfact # \alpha_s emission scale factors
2870 %(sys_matchscale)s = sys_matchscale # variation of merging scale
2871 # PDF sets and number of members (0 or none for all members).
2872 %(sys_pdf)s = sys_pdf # list of pdf sets. (errorset not valid for syscalc)
2873 # MSTW2008nlo68cl.LHgrid 1 = sys_pdf
2874 #
2875 """,
2876 template_off= '# Syscalc is deprecated but to see the associate options type\'update syscalc\''),
2877
2878
2879 runblock(name='ecut', fields=('ej','eb','ea','el','ejmax','ebmax','eamax','elmax','e_min_pdg','e_max_pdg'),
2880 template_on=\
2881 """#*********************************************************************
2882 # Minimum and maximum E's (in the center of mass frame) *
2883 #*********************************************************************
2884 %(ej)s = ej ! minimum E for the jets
2885 %(eb)s = eb ! minimum E for the b
2886 %(ea)s = ea ! minimum E for the photons
2887 %(el)s = el ! minimum E for the charged leptons
2888 %(ejmax)s = ejmax ! maximum E for the jets
2889 %(ebmax)s = ebmax ! maximum E for the b
2890 %(eamax)s = eamax ! maximum E for the photons
2891 %(elmax)s = elmax ! maximum E for the charged leptons
2892 %(e_min_pdg)s = e_min_pdg ! E cut for other particles (use pdg code). Applied on particle and anti-particle
2893 %(e_max_pdg)s = e_max_pdg ! E cut for other particles (syntax e.g. {6: 100, 25: 50})
2894 """,
2895 template_off= '#\n# For display option for energy cut in the partonic center of mass frame type \'update ecut\'\n#'),
2896
2897
2898 runblock(name='frame', fields=('me_frame'),
2899 template_on=\
2900 """#*********************************************************************
2901 # Frame where to evaluate the matrix-element (not the cut!) for polarization
2902 #*********************************************************************
2903 %(me_frame)s = me_frame ! list of particles to sum-up to define the rest-frame
2904 ! in which to evaluate the matrix-element
2905 ! [1,2] means the partonic center of mass
2906 """,
2907 template_off= ''),
2908
2909 runblock(name='mlm', fields=('ickkw','alpsfact','chcluster','asrwgtflavor','auto_ptj_mjj','xqcut'),
2910 template_on=\
2911 """#*********************************************************************
2912 # Matching parameter (MLM only)
2913 #*********************************************************************
2914 %(ickkw)s = ickkw ! 0 no matching, 1 MLM
2915 %(alpsfact)s = alpsfact ! scale factor for QCD emission vx
2916 %(chcluster)s = chcluster ! cluster only according to channel diag
2917 %(asrwgtflavor)s = asrwgtflavor ! highest quark flavor for a_s reweight
2918 %(auto_ptj_mjj)s = auto_ptj_mjj ! Automatic setting of ptj and mjj if xqcut >0
2919 ! (turn off for VBF and single top processes)
2920 %(xqcut)s = xqcut ! minimum kt jet measure between partons
2921 """,
2922 template_off='# To see MLM/CKKW merging options: type "update MLM" or "update CKKW"'),
2923
2924
2925 runblock(name='ckkw', fields=('ktdurhham','dparameter','ptlund','pdgs_for_merging_cut'),
2926 template_on=\
2927 """#***********************************************************************
2928 # Turn on either the ktdurham or ptlund cut to activate *
2929 # CKKW(L) merging with Pythia8 [arXiv:1410.3012, arXiv:1109.4829] *
2930 #***********************************************************************
2931 %(ktdurham)s = ktdurham
2932 %(dparameter)s = dparameter
2933 %(ptlund)s = ptlund
2934 %(pdgs_for_merging_cut)s = pdgs_for_merging_cut ! PDGs for two cuts above
2935 """,
2936 template_off=''),
2937
2938 runblock(name='psoptim', fields=('job_strategy', 'hard_survey',
2939 'tmin_for_channel', 'survey_splitting',
2940 'survey_nchannel_per_job', 'refine_evt_by_job'
2941 'global_flag','aloha_flag', 'matrix_flag'
2942 ),
2943 template_on=\
2944 """#*********************************************************************
2945 # Phase-Space Optim (advanced)
2946 #*********************************************************************
2947 %(job_strategy)s = job_strategy ! see appendix of 1507.00020 (page 26)
2948 %(hard_survey)s = hard_survey ! force to have better estimate of the integral at survey for difficult mode like interference
2949 %(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
2950 %(survey_splitting)s = survey_splitting ! for loop-induced control how many core are used at survey for the computation of a single iteration.
2951 %(survey_nchannel_per_job)s = survey_nchannel_per_job ! control how many Channel are integrated inside a single job on cluster/multicore
2952 %(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)
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)
2999 self.add_param("scale", 91.1880)
3000 self.add_param("dsqrt_q2fact1", 91.1880, fortran_name="sf1")
3001 self.add_param("dsqrt_q2fact2", 91.1880, fortran_name="sf2")
3002 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",
3003 allowed=[-1,0,1,2,3,4])
3004
3005
3006 self.add_param("bias_module", 'None', include=False)
3007 self.add_param('bias_parameters', {'__type__':1.0}, include='BIAS/bias.inc')
3008
3009
3010 self.add_param("scalefact", 1.0)
3011 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.")
3012 self.add_param("highestmult", 1, fortran_name="nhmult", hidden=True)
3013 self.add_param("ktscheme", 1, hidden=True)
3014 self.add_param("alpsfact", 1.0, hidden=True)
3015 self.add_param("chcluster", False, hidden=True)
3016 self.add_param("pdfwgt", True, hidden=True)
3017 self.add_param("asrwgtflavor", 5, hidden=True, comment = 'highest quark flavor for a_s reweighting in MLM')
3018 self.add_param("clusinfo", True, hidden=True)
3019
3020 self.add_param("lhe_version", 3.0, hidden=True)
3021 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")
3022 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")
3023 self.add_param('frame_id', 6, system=True)
3024 self.add_param("event_norm", "average", allowed=['sum','average', 'unity'],
3025 include=False, sys_default='sum', hidden=True)
3026
3027 self.add_param("auto_ptj_mjj", True, hidden=True)
3028 self.add_param("bwcutoff", 15.0)
3029 self.add_param("cut_decays", False, cut='d')
3030 self.add_param("nhel", 0, include=False)
3031
3032 self.add_param("ptj", 20.0, cut='j')
3033 self.add_param("ptb", 0.0, cut='b')
3034 self.add_param("pta", 10.0, cut='a')
3035 self.add_param("ptl", 10.0, cut='l')
3036 self.add_param("misset", 0.0, cut='n')
3037 self.add_param("ptheavy", 0.0, cut='H', comment='this cut apply on particle heavier than 10 GeV')
3038 self.add_param("ptonium", 1.0, legacy=True)
3039 self.add_param("ptjmax", -1.0, cut='j')
3040 self.add_param("ptbmax", -1.0, cut='b')
3041 self.add_param("ptamax", -1.0, cut='a')
3042 self.add_param("ptlmax", -1.0, cut='l')
3043 self.add_param("missetmax", -1.0, cut='n')
3044
3045 self.add_param("ej", 0.0, cut='j', hidden=True)
3046 self.add_param("eb", 0.0, cut='b', hidden=True)
3047 self.add_param("ea", 0.0, cut='a', hidden=True)
3048 self.add_param("el", 0.0, cut='l', hidden=True)
3049 self.add_param("ejmax", -1.0, cut='j', hidden=True)
3050 self.add_param("ebmax", -1.0, cut='b', hidden=True)
3051 self.add_param("eamax", -1.0, cut='a', hidden=True)
3052 self.add_param("elmax", -1.0, cut='l', hidden=True)
3053
3054 self.add_param("etaj", 5.0, cut='j')
3055 self.add_param("etab", -1.0, cut='b')
3056 self.add_param("etaa", 2.5, cut='a')
3057 self.add_param("etal", 2.5, cut='l')
3058 self.add_param("etaonium", 0.6, legacy=True)
3059 self.add_param("etajmin", 0.0, cut='a')
3060 self.add_param("etabmin", 0.0, cut='b')
3061 self.add_param("etaamin", 0.0, cut='a')
3062 self.add_param("etalmin", 0.0, cut='l')
3063
3064 self.add_param("drjj", 0.4, cut='jj')
3065 self.add_param("drbb", 0.0, cut='bb')
3066 self.add_param("drll", 0.4, cut='ll')
3067 self.add_param("draa", 0.4, cut='aa')
3068 self.add_param("drbj", 0.0, cut='bj')
3069 self.add_param("draj", 0.4, cut='aj')
3070 self.add_param("drjl", 0.4, cut='jl')
3071 self.add_param("drab", 0.0, cut='ab')
3072 self.add_param("drbl", 0.0, cut='bl')
3073 self.add_param("dral", 0.4, cut='al')
3074 self.add_param("drjjmax", -1.0, cut='jj')
3075 self.add_param("drbbmax", -1.0, cut='bb')
3076 self.add_param("drllmax", -1.0, cut='ll')
3077 self.add_param("draamax", -1.0, cut='aa')
3078 self.add_param("drbjmax", -1.0, cut='bj')
3079 self.add_param("drajmax", -1.0, cut='aj')
3080 self.add_param("drjlmax", -1.0, cut='jl')
3081 self.add_param("drabmax", -1.0, cut='ab')
3082 self.add_param("drblmax", -1.0, cut='bl')
3083 self.add_param("dralmax", -1.0, cut='al')
3084
3085 self.add_param("mmjj", 0.0, cut='jj')
3086 self.add_param("mmbb", 0.0, cut='bb')
3087 self.add_param("mmaa", 0.0, cut='aa')
3088 self.add_param("mmll", 0.0, cut='ll')
3089 self.add_param("mmjjmax", -1.0, cut='jj')
3090 self.add_param("mmbbmax", -1.0, cut='bb')
3091 self.add_param("mmaamax", -1.0, cut='aa')
3092 self.add_param("mmllmax", -1.0, cut='ll')
3093 self.add_param("mmnl", 0.0, cut='LL')
3094 self.add_param("mmnlmax", -1.0, cut='LL')
3095
3096 self.add_param("ptllmin", 0.0, cut='ll')
3097 self.add_param("ptllmax", -1.0, cut='ll')
3098 self.add_param("xptj", 0.0, cut='jj')
3099 self.add_param("xptb", 0.0, cut='bb')
3100 self.add_param("xpta", 0.0, cut='aa')
3101 self.add_param("xptl", 0.0, cut='ll')
3102
3103 self.add_param("ptj1min", 0.0, cut='jj')
3104 self.add_param("ptj1max", -1.0, cut='jj')
3105 self.add_param("ptj2min", 0.0, cut='jj')
3106 self.add_param("ptj2max", -1.0, cut='jj')
3107 self.add_param("ptj3min", 0.0, cut='jjj')
3108 self.add_param("ptj3max", -1.0, cut='jjj')
3109 self.add_param("ptj4min", 0.0, cut='j'*4)
3110 self.add_param("ptj4max", -1.0, cut='j'*4)
3111 self.add_param("cutuse", 0, cut='jj')
3112
3113 self.add_param("ptl1min", 0.0, cut='l'*2)
3114 self.add_param("ptl1max", -1.0, cut='l'*2)
3115 self.add_param("ptl2min", 0.0, cut='l'*2)
3116 self.add_param("ptl2max", -1.0, cut='l'*2)
3117 self.add_param("ptl3min", 0.0, cut='l'*3)
3118 self.add_param("ptl3max", -1.0, cut='l'*3)
3119 self.add_param("ptl4min", 0.0, cut='l'*4)
3120 self.add_param("ptl4max", -1.0, cut='l'*4)
3121
3122 self.add_param("htjmin", 0.0, cut='j'*2)
3123 self.add_param("htjmax", -1.0, cut='j'*2)
3124 self.add_param("ihtmin", 0.0, cut='J'*2)
3125 self.add_param("ihtmax", -1.0, cut='J'*2)
3126 self.add_param("ht2min", 0.0, cut='J'*3)
3127 self.add_param("ht3min", 0.0, cut='J'*3)
3128 self.add_param("ht4min", 0.0, cut='J'*4)
3129 self.add_param("ht2max", -1.0, cut='J'*3)
3130 self.add_param("ht3max", -1.0, cut='J'*3)
3131 self.add_param("ht4max", -1.0, cut='J'*4)
3132
3133 self.add_param("ptgmin", 0.0, cut='aj')
3134 self.add_param("r0gamma", 0.4, hidden=True)
3135 self.add_param("xn", 1.0, hidden=True)
3136 self.add_param("epsgamma", 1.0, hidden=True)
3137 self.add_param("isoem", True, hidden=True)
3138 self.add_param("xetamin", 0.0, cut='jj')
3139 self.add_param("deltaeta", 0.0, cut='j'*2)
3140 self.add_param("ktdurham", -1.0, fortran_name="kt_durham", cut='j')
3141 self.add_param("dparameter", 0.4, fortran_name="d_parameter", cut='j')
3142 self.add_param("ptlund", -1.0, fortran_name="pt_lund", cut='j')
3143 self.add_param("pdgs_for_merging_cut", [21, 1, 2, 3, 4, 5, 6], hidden=True)
3144 self.add_param("maxjetflavor", 4)
3145 self.add_param("xqcut", 0.0, cut=True)
3146 self.add_param("use_syst", True)
3147 self.add_param('systematics_program', 'systematics', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics, syscalc')
3148 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.')
3149
3150 self.add_param("sys_scalefact", "0.5 1 2", include=False, hidden=True)
3151 self.add_param("sys_alpsfact", "None", include=False, hidden=True)
3152 self.add_param("sys_matchscale", "auto", include=False, hidden=True)
3153 self.add_param("sys_pdf", "errorset", include=False, hidden=True)
3154 self.add_param("sys_scalecorrelation", -1, include=False, hidden=True)
3155
3156
3157 self.add_param('gridrun', False, hidden=True)
3158 self.add_param('fixed_couplings', True, hidden=True)
3159 self.add_param('mc_grouped_subproc', True, hidden=True)
3160 self.add_param('xmtcentral', 0.0, hidden=True, fortran_name="xmtc")
3161 self.add_param('d', 1.0, hidden=True)
3162 self.add_param('gseed', 0, hidden=True, include=False)
3163 self.add_param('issgridfile', '', hidden=True)
3164
3165 self.add_param('job_strategy', 0, hidden=True, include=False, allowed=[0,1,2], comment='see appendix of 1507.00020 (page 26)')
3166 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')
3167 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')
3168 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.")
3169 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.")
3170 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")
3171 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)")
3172 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")
3173
3174 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--')
3175 self.add_param('hel_filtering', True, hidden=True, include=False, comment='filter in advance the zero helicities when doing helicity per helicity optimization.')
3176 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.')
3177 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.')
3178 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")
3179 self.add_param('global_flag', '-O', include=False, hidden=True, comment='global fortran compilation flag, suggestion -fbound-check')
3180 self.add_param('aloha_flag', '', include=False, hidden=True, comment='global fortran compilation flag, suggestion: -ffast-math')
3181 self.add_param('matrix_flag', '', include=False, hidden=True, comment='global fortran compilation flag, suggestion: -O3')
3182
3183
3184
3185 self.add_param('pt_min_pdg',{'__type__':0.}, include=False, cut=True)
3186 self.add_param('pt_max_pdg',{'__type__':0.}, include=False, cut=True)
3187 self.add_param('E_min_pdg',{'__type__':0.}, include=False, hidden=True,cut=True)
3188 self.add_param('E_max_pdg',{'__type__':0.}, include=False, hidden=True,cut=True)
3189 self.add_param('eta_min_pdg',{'__type__':0.}, include=False,cut=True)
3190 self.add_param('eta_max_pdg',{'__type__':0.}, include=False,cut=True)
3191 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True)
3192 self.add_param('mxx_only_part_antipart', {'default':False}, include=False)
3193
3194 self.add_param('pdg_cut',[0], system=True)
3195 self.add_param('ptmin4pdg',[0.], system=True)
3196 self.add_param('ptmax4pdg',[-1.], system=True)
3197 self.add_param('Emin4pdg',[0.], system=True)
3198 self.add_param('Emax4pdg',[-1.], system=True)
3199 self.add_param('etamin4pdg',[0.], system=True)
3200 self.add_param('etamax4pdg',[-1.], system=True)
3201 self.add_param('mxxmin4pdg',[-1.], system=True)
3202 self.add_param('mxxpart_antipart', [False], system=True)
3203
3204
3205
3207 """ """
3208
3209 super(RunCardLO, self).check_validity()
3210
3211
3212
3213
3214 if 'nhel' not in self:
3215 raise InvalidRunCard("Parameter nhel is not defined in the run_card.")
3216 if self['nhel'] not in [1,0]:
3217 raise InvalidRunCard("Parameter nhel can only be '0' or '1', "+\
3218 "not %s." % self['nhel'])
3219 if int(self['maxjetflavor']) > 6:
3220 raise InvalidRunCard('maxjetflavor should be lower than 5! (6 is partly supported)')
3221
3222 if len(self['pdgs_for_merging_cut']) > 1000:
3223 raise InvalidRunCard("The number of elements in "+\
3224 "'pdgs_for_merging_cut' should not exceed 1000.")
3225
3226
3227 if self['ptgmin'] > 0:
3228 if self['pta'] > 0:
3229 logger.warning('pta cut discarded since photon isolation is used')
3230 self['pta'] = 0.0
3231 if self['draj'] > 0:
3232 logger.warning('draj cut discarded since photon isolation is used')
3233 self['draj'] = 0.0
3234
3235
3236 if self['gridrun']:
3237 self['iseed'] = self['gseed']
3238
3239
3240 if self['use_syst']:
3241 if self['scalefact'] != 1.0:
3242 logger.warning('Since use_syst=T, We change the value of \'scalefact\' to 1')
3243 self['scalefact'] = 1.0
3244
3245
3246 if self['ickkw'] > 0:
3247 if self['ickkw'] != 1:
3248 logger.critical('ickkw >1 is pure alpha and only partly implemented.')
3249 import madgraph.interface.extended_cmd as basic_cmd
3250 answer = basic_cmd.smart_input('Do you really want to continue', allow_arg=['y','n'], default='n')
3251 if answer !='y':
3252 raise InvalidRunCard('ickkw>1 is still in alpha')
3253 if self['use_syst']:
3254
3255 if self['alpsfact'] != 1.0:
3256 logger.warning('Since use_syst=T, We change the value of \'alpsfact\' to 1')
3257 self['alpsfact'] =1.0
3258 if self['maxjetflavor'] == 6:
3259 raise InvalidRunCard('maxjetflavor at 6 is NOT supported for matching!')
3260 if self['ickkw'] == 2:
3261
3262 self.get_default('highestmult', log_level=20)
3263 self.get_default('issgridfile', 'issudgrid.dat', log_level=20)
3264 if self['xqcut'] > 0:
3265 if self['ickkw'] == 0:
3266 logger.error('xqcut>0 but ickkw=0. Potentially not fully consistent setup. Be carefull')
3267 time.sleep(5)
3268 if self['drjj'] != 0:
3269 if 'drjj' in self.user_set:
3270 logger.warning('Since icckw>0, We change the value of \'drjj\' to 0')
3271 self['drjj'] = 0
3272 if self['drjl'] != 0:
3273 if 'drjl' in self.user_set:
3274 logger.warning('Since icckw>0, We change the value of \'drjl\' to 0')
3275 self['drjl'] = 0
3276 if not self['auto_ptj_mjj']:
3277 if self['mmjj'] > self['xqcut']:
3278 logger.warning('mmjj > xqcut (and auto_ptj_mjj = F). MMJJ set to 0')
3279 self['mmjj'] = 0.0
3280
3281
3282 if self['pdlabel'] == 'lhapdf':
3283
3284 self.get_default('lhaid', log_level=20)
3285
3286
3287 if self['lpp1'] not in [1,2]:
3288 if self['nb_proton1'] !=1 or self['nb_neutron1'] !=0:
3289 raise InvalidRunCard( "Heavy ion mode is only supported for lpp1=1/2")
3290 if self['lpp2'] not in [1,2]:
3291 if self['nb_proton2'] !=1 or self['nb_neutron2'] !=0:
3292 raise InvalidRunCard( "Heavy ion mode is only supported for lpp2=1/2")
3293
3294
3295 for i in [1,2]:
3296 if abs(self['lpp%s' % i ]) in [3,4] and self['dsqrt_q2fact%s'%i] == 91.188:
3297 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)
3298 time.sleep(5)
3299
3300 if abs(self['lpp%s' % i ]) == 2 and self['dsqrt_q2fact%s'%i] == 91.188:
3301 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)
3302 time.sleep(5)
3303
3304
3305 if abs(self['lpp1']) in [2, 3,4] and abs(self['lpp2']) in [2, 3,4] and not self['fixed_fac_scale']:
3306 raise InvalidRunCard("Having both beam in elastic photon mode requires fixed_fac_scale to be on True [since this is use as cutoff]")
3307
3308 if six.PY2 and self['hel_recycling']:
3309 self['hel_recycling'] = False
3310 logger.warning("""Helicity recycling optimization requires Python3. This optimzation is therefore deactivated automatically.
3311 In general this optimization speed up the computation be a factor of two.""")
3312 elif self['hel_recycling']:
3313 if self['gridpack']:
3314 self.set(self, "hel_zeroamp", True, changeifuserset=False, user=False, raiseerror=False)
3315
3316
3317 for i in [1,2]:
3318 if self['lpp%s' % i ] not in [1,2]:
3319 continue
3320 if self['mass_ion%i' % i] == -1:
3321 if self['ebeam%i' % i] < 0.938:
3322 if self['ebeam%i' %i] == 0:
3323 logger.warning("At rest proton mode set: Energy beam set to 0.938")
3324 self.set('ebeam%i' %i, 0.938)
3325 else:
3326 raise InvalidRunCard("Energy for beam %i lower than proton mass. Please fix this")
3327 elif self['ebeam%i' % i] < self['mass_ion%i' % i]:
3328 if self['ebeam%i' %i] == 0:
3329 logger.warning("At rest ion mode set: Energy beam set to %s" % self['mass_ion%i' % i])
3330 self.set('ebeam%i' %i, self['mass_ion%i' % i])
3331
3332
3333
3334 if self['tmin_for_channel'] == 0:
3335 raise InvalidRunCard('tmin_for_channel can not be set to 0.')
3336 elif self['tmin_for_channel'] > 0:
3337 logger.warning('tmin_for_channel should be negative. Will be using -%f instead' % self['tmin_for_channel'])
3338 self.set('tmin_for_channel', -self['tmin_for_channel'])
3339
3340
3341
3342
3344
3345
3346 self['frame_id'] = sum(2**(n) for n in self['me_frame'])
3347
3348
3349 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys()) +
3350 list(self['e_min_pdg'].keys()) +list(self['e_max_pdg'].keys()) +
3351 list(self['eta_min_pdg'].keys()) +list(self['eta_max_pdg'].keys())+
3352 list(self['mxx_min_pdg'].keys()) + list(self['mxx_only_part_antipart'].keys()))
3353 pdg_to_cut.discard('__type__')
3354 pdg_to_cut.discard('default')
3355 if len(pdg_to_cut)>25:
3356 raise Exception("Maximum 25 different pdgs are allowed for pdg specific cut")
3357
3358 if any(int(pdg)<0 for pdg in pdg_to_cut):
3359 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
3360 raise MadGraph5Error('Some PDG specific cuts are defined with negative pdg code')
3361
3362
3363 if any(pdg in pdg_to_cut for pdg in [1,2,3,4,5,21,22,11,13,15]):
3364 raise Exception("Can not use PDG related cut for light quark/b quark/lepton/gluon/photon")
3365
3366 if pdg_to_cut:
3367 self['pdg_cut'] = list(pdg_to_cut)
3368 self['ptmin4pdg'] = []
3369 self['Emin4pdg'] = []
3370 self['etamin4pdg'] =[]
3371 self['ptmax4pdg'] = []
3372 self['Emax4pdg'] = []
3373 self['etamax4pdg'] =[]
3374 self['mxxmin4pdg'] =[]
3375 self['mxxpart_antipart'] = []
3376 for pdg in self['pdg_cut']:
3377 for var in ['pt','e','eta', 'Mxx']:
3378 for minmax in ['min', 'max']:
3379 if var in ['Mxx'] and minmax =='max':
3380 continue
3381 new_var = '%s%s4pdg' % (var, minmax)
3382 old_var = '%s_%s_pdg' % (var, minmax)
3383 default = 0. if minmax=='min' else -1.
3384 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3385
3386 old_var = 'mxx_only_part_antipart'
3387 new_var = 'mxxpart_antipart'
3388 if 'default' in self[old_var]:
3389 default = self[old_var]['default']
3390 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3391 else:
3392 if str(pdg) not in self[old_var]:
3393 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
3394 self[new_var].append(self[old_var][str(pdg)])
3395 else:
3396 self['pdg_cut'] = [0]
3397 self['ptmin4pdg'] = [0.]
3398 self['Emin4pdg'] = [0.]
3399 self['etamin4pdg'] =[0.]
3400 self['ptmax4pdg'] = [-1.]
3401 self['Emax4pdg'] = [-1.]
3402 self['etamax4pdg'] =[-1.]
3403 self['mxxmin4pdg'] =[0.]
3404 self['mxxpart_antipart'] = [False]
3405
3406
3407
3409 """Rules
3410 process 1->N all cut set on off.
3411 loop_induced -> MC over helicity
3412 e+ e- beam -> lpp:0 ebeam:500
3413 p p beam -> set maxjetflavor automatically
3414 more than one multiplicity: ickkw=1 xqcut=30 use_syst=F
3415 """
3416
3417
3418 if proc_characteristic['loop_induced']:
3419 self['nhel'] = 1
3420 self['pdgs_for_merging_cut'] = proc_characteristic['colored_pdgs']
3421
3422 if proc_characteristic['ninitial'] == 1:
3423
3424 self.remove_all_cut()
3425 self['use_syst'] = False
3426 else:
3427
3428
3429 beam_id = set()
3430 beam_id_split = [set(), set()]
3431 for proc in proc_def:
3432 for oneproc in proc:
3433 for i,leg in enumerate(oneproc['legs']):
3434 if not leg['state']:
3435 beam_id_split[i].add(leg['id'])
3436 beam_id.add(leg['id'])
3437
3438 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3439 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
3440 self['maxjetflavor'] = maxjetflavor
3441 self['asrwgtflavor'] = maxjetflavor
3442
3443 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3444
3445 if any(id in beam_id for id in [11,-11,13,-13]):
3446 self.display_block.append('beam_pol')
3447 if any(id in beam_id_split[0] for id in [11,-11,13,-13]):
3448 self['lpp1'] = 0
3449 self['lpp2'] = 1
3450 self['ebeam1'] = '1k'
3451 self['ebeam2'] = '6500'
3452 else:
3453 self['lpp1'] = 1
3454 self['lpp2'] = 0
3455 self['ebeam1'] = '6500'
3456 self['ebeam2'] = '1k'
3457
3458 elif any(id in beam_id for id in [11,-11,13,-13]):
3459 self['lpp1'] = 0
3460 self['lpp2'] = 0
3461 self['ebeam1'] = 500
3462 self['ebeam2'] = 500
3463 self['use_syst'] = False
3464 if set([ abs(i) for i in beam_id_split[0]]) == set([ abs(i) for i in beam_id_split[1]]):
3465 self.display_block.append('ecut')
3466 self.display_block.append('beam_pol')
3467 else:
3468 self['lpp1'] = 0
3469 self['lpp2'] = 0
3470 self['use_syst'] = False
3471 self.display_block.append('beam_pol')
3472 self.display_block.append('ecut')
3473
3474
3475 if any(id in beam_id for id in [12,-12,14,-14,16,-16]):
3476 self.display_block.append('beam_pol')
3477 if any(id in beam_id_split[0] for id in [12,14,16]):
3478 self['lpp1'] = 0
3479 self['ebeam1'] = '1k'
3480 self['polbeam1'] = -100
3481 if not all(id in [12,14,16] for id in beam_id_split[0]):
3482 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1]. %s')
3483 elif any(id in beam_id_split[0] for id in [-12,-14,-16]):
3484 self['lpp1'] = 0
3485 self['ebeam1'] = '1k'
3486 self['polbeam1'] = 100
3487 if not all(id in [-12,-14,-16] for id in beam_id_split[0]):
3488 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1].')
3489 if any(id in beam_id_split[1] for id in [12,14,16]):
3490 self['lpp2'] = 0
3491 self['ebeam2'] = '1k'
3492 self['polbeam2'] = -100
3493 if not all(id in [12,14,16] for id in beam_id_split[1]):
3494 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].')
3495 if any(id in beam_id_split[1] for id in [-12,-14,-16]):
3496 self['lpp2'] = 0
3497 self['ebeam2'] = '1k'
3498 self['polbeam2'] = 100
3499 if not all(id in [-12,-14,-16] for id in beam_id_split[1]):
3500 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].')
3501
3502
3503 min_particle = 99
3504 max_particle = 0
3505 for proc in proc_def:
3506 min_particle = min(len(proc[0]['legs']), min_particle)
3507 max_particle = max(len(proc[0]['legs']), max_particle)
3508 if min_particle != max_particle:
3509
3510 for procmin in proc_def:
3511 if len(procmin[0]['legs']) != min_particle:
3512 continue
3513 else:
3514 idsmin = [l['id'] for l in procmin[0]['legs']]
3515 break
3516 matching = False
3517 for procmax in proc_def:
3518 if len(procmax[0]['legs']) != max_particle:
3519 continue
3520 idsmax = [l['id'] for l in procmax[0]['legs']]
3521 for i in idsmin:
3522 if i not in idsmax:
3523 continue
3524 else:
3525 idsmax.remove(i)
3526 for j in idsmax:
3527 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
3528 break
3529 else:
3530
3531 matching=True
3532 break
3533
3534 if matching:
3535 self['ickkw'] = 1
3536 self['xqcut'] = 30
3537
3538 self['drjj'] = 0
3539 self['drjl'] = 0
3540 self['sys_alpsfact'] = "0.5 1 2"
3541 self['systematics_arguments'].append('--alps=0.5,1,2')
3542 self.display_block.append('mlm')
3543 self.display_block.append('ckkw')
3544 self['dynamical_scale_choice'] = -1
3545
3546
3547
3548
3549 no_systematics = False
3550 interference = False
3551 for proc in proc_def:
3552 for oneproc in proc:
3553 if '^2' in oneproc.nice_string():
3554 interference = True
3555 break
3556 else:
3557 continue
3558 break
3559
3560
3561 if interference or no_systematics:
3562 self['use_syst'] = False
3563 self['systematics_program'] = 'none'
3564 if interference:
3565 self['dynamical_scale_choice'] = 3
3566 self['sde_strategy'] = 2
3567
3568
3569
3570
3571
3572 if proc_characteristic['single_color']:
3573 self['sde_strategy'] = 2
3574 else:
3575
3576 is_multijet = True
3577 jet_id = [21] + list(range(1, self['maxjetflavor']+1))
3578 for proc in proc_def:
3579 if any(abs(j.get('id')) not in jet_id for j in proc[0]['legs']):
3580 is_multijet = False
3581 break
3582 if is_multijet:
3583 self['sde_strategy'] = 2
3584
3585
3586
3587 for plist in proc_def:
3588 for proc in plist:
3589 for l in proc.get('legs') + proc.get('legs_with_decays'):
3590 if l.get('polarization'):
3591 model = proc.get('model')
3592 particle = model.get_particle(l.get('id'))
3593 if particle.get('mass').lower() != 'zero':
3594 self.display_block.append('frame')
3595 break
3596 else:
3597 continue
3598 break
3599 else:
3600 continue
3601 break
3602
3603 if 'MLM' in proc_characteristic['limitations']:
3604 if self['dynamical_scale_choice'] == -1:
3605 self['dynamical_scale_choice'] = 3
3606 if self['ickkw'] == 1:
3607 logger.critical("MLM matching/merging not compatible with the model! You need to use another method to remove the double counting!")
3608 self['ickkw'] = 0
3609
3610
3611
3612 cut_class = collections.defaultdict(int)
3613 for proc in proc_def:
3614 for oneproc in proc:
3615 one_proc_cut = collections.defaultdict(int)
3616 ids = oneproc.get_final_ids_after_decay()
3617 if oneproc['decay_chains']:
3618 cut_class['d'] = 1
3619 for pdg in ids:
3620 if pdg == 22:
3621 one_proc_cut['a'] +=1
3622 elif abs(pdg) <= self['maxjetflavor']:
3623 one_proc_cut['j'] += 1
3624 one_proc_cut['J'] += 1
3625 elif abs(pdg) <= 5:
3626 one_proc_cut['b'] += 1
3627 one_proc_cut['J'] += 1
3628 elif abs(pdg) in [11,13,15]:
3629 one_proc_cut['l'] += 1
3630 one_proc_cut['L'] += 1
3631 elif abs(pdg) in [12,14,16]:
3632 one_proc_cut['n'] += 1
3633 one_proc_cut['L'] += 1
3634 elif str(oneproc.get('model').get_particle(pdg)['mass']) != 'ZERO':
3635 one_proc_cut['H'] += 1
3636
3637 for key, nb in one_proc_cut.items():
3638 cut_class[key] = max(cut_class[key], nb)
3639 self.cut_class = dict(cut_class)
3640 self.cut_class[''] = True
3641
3642 - def write(self, output_file, template=None, python_template=False,
3643 **opt):
3644 """Write the run_card in output_file according to template
3645 (a path to a valid run_card)"""
3646
3647 if not template:
3648 if not MADEVENT:
3649 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
3650 'run_card.dat')
3651 python_template = True
3652 else:
3653 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
3654 python_template = False
3655
3656
3657 hid_lines = {'default':True}
3658 if isinstance(output_file, str):
3659 if 'default' in output_file:
3660 if self.cut_class:
3661 hid_lines['default'] = False
3662 for key in self.cut_class:
3663 nb = self.cut_class[key]
3664 for i in range(1,nb+1):
3665 hid_lines[key*i] = True
3666 for k1,k2 in ['bj', 'bl', 'al', 'jl', 'ab', 'aj']:
3667 if self.cut_class.get(k1) and self.cut_class.get(k2):
3668 hid_lines[k1+k2] = True
3669
3670 super(RunCardLO, self).write(output_file, template=template,
3671 python_template=python_template,
3672 template_options=hid_lines,
3673 **opt)
3674
3678
3680 """ A class to store a MadAnalysis5 card. Very basic since it is basically
3681 free format."""
3682
3683 _MG5aMC_escape_tag = '@MG5aMC'
3684
3685 _default_hadron_inputs = ['*.hepmc', '*.hep', '*.stdhep', '*.lhco','*.root']
3686 _default_parton_inputs = ['*.lhe']
3687 _skip_analysis = False
3688
3689 @classmethod
3691 """ Checks from the type of an event file whether it can be reconstructed or not."""
3692 return not (file_path.endswith('.lhco') or file_path.endswith('.lhco.gz') or \
3693 file_path.endswith('.root') or file_path.endswith('.root.gz'))
3694
3695 @classmethod
3697 """ A method returning the structure of an empty analysis """
3698 return {'commands':[],
3699 'reconstructions':[]}
3700
3701 @classmethod
3703 """ A method returning the structure of an empty reconstruction """
3704 return {'commands':[],
3705 'reco_output':'lhe'}
3706
3708 """define the default value"""
3709 self['mode'] = 'parton'
3710 self['inputs'] = []
3711
3712 self['stdout_lvl'] = None
3713
3714
3715
3716
3717
3718
3719
3720 self['analyses'] = {}
3721
3722
3723 self['recasting'] = {'commands':[],'card':[]}
3724
3725
3726 self['reconstruction'] = {'lhco_input':
3727 MadAnalysis5Card.empty_reconstruction(),
3728 'root_input':
3729 MadAnalysis5Card.empty_reconstruction()}
3730 self['reconstruction']['lhco_input']['reco_output']='lhco'
3731 self['reconstruction']['root_input']['reco_output']='root'
3732
3733
3734 self['order'] = []
3735
3736 - def __init__(self, finput=None,mode=None):
3737 if isinstance(finput, self.__class__):
3738 dict.__init__(self, finput)
3739 assert list(finput.__dict__.keys())
3740 for key in finput.__dict__:
3741 setattr(self, key, copy.copy(getattr(finput, key)) )
3742 return
3743 else:
3744 dict.__init__(self)
3745
3746
3747 self.default_setup()
3748 if not mode is None:
3749 self['mode']=mode
3750
3751
3752 if isinstance(finput, (file, str, StringIO.StringIO)):
3753 self.read(finput, mode=mode)
3754
3755 - def read(self, input, mode=None):
3756 """ Read an MA5 card"""
3757
3758 if mode not in [None,'parton','hadron']:
3759 raise MadGraph5Error('A MadAnalysis5Card can be read online the modes'+
3760 "'parton' or 'hadron'")
3761 card_mode = mode
3762
3763 if isinstance(input, (file, StringIO.StringIO)):
3764 input_stream = input
3765 elif isinstance(input, str):
3766 if not os.path.isfile(input):
3767 raise InvalidMadAnalysis5Card("Cannot read the MadAnalysis5 card."+\
3768 "File '%s' not found."%input)
3769 if mode is None and 'hadron' in input:
3770 card_mode = 'hadron'
3771 input_stream = open(input,'r')
3772 else:
3773 raise MadGraph5Error('Incorrect input for the read function of'+\
3774 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(input)))
3775
3776
3777 self.__init__()
3778 current_name = 'default'
3779 current_type = 'analyses'
3780 for line in input_stream:
3781
3782 if line.startswith('#'):
3783 continue
3784 if line.endswith('\n'):
3785 line = line[:-1]
3786 if line.strip()=='':
3787 continue
3788 if line.startswith(self._MG5aMC_escape_tag):
3789 try:
3790 option,value = line[len(self._MG5aMC_escape_tag):].split('=')
3791 value = value.strip()
3792 except ValueError:
3793 option = line[len(self._MG5aMC_escape_tag):]
3794 option = option.strip()
3795
3796 if option=='inputs':
3797 self['inputs'].extend([v.strip() for v in value.split(',')])
3798
3799 elif option == 'skip_analysis':
3800 self._skip_analysis = True
3801
3802 elif option=='stdout_lvl':
3803 try:
3804 self['stdout_lvl']=int(value)
3805 except ValueError:
3806 try:
3807 self['stdout_lvl']=eval(value)
3808 except:
3809 try:
3810 self['stdout_lvl']=eval('logging.%s'%value)
3811 except:
3812 raise InvalidMadAnalysis5Card(
3813 "MA5 output level specification '%s' is incorrect."%str(value))
3814
3815 elif option=='analysis_name':
3816 current_type = 'analyses'
3817 current_name = value
3818 if current_name in self[current_type]:
3819 raise InvalidMadAnalysis5Card(
3820 "Analysis '%s' already defined in MadAnalysis5 card"%current_name)
3821 else:
3822 self[current_type][current_name] = MadAnalysis5Card.empty_analysis()
3823
3824 elif option=='set_reconstructions':
3825 try:
3826 reconstructions = eval(value)
3827 if not isinstance(reconstructions, list):
3828 raise
3829 except:
3830 raise InvalidMadAnalysis5Card("List of reconstructions"+\
3831 " '%s' could not be parsed in MadAnalysis5 card."%value)
3832 if current_type!='analyses' and current_name not in self[current_type]:
3833 raise InvalidMadAnalysis5Card("A list of reconstructions"+\
3834 "can only be defined in the context of an "+\
3835 "analysis in a MadAnalysis5 card.")
3836 self[current_type][current_name]['reconstructions']=reconstructions
3837 continue
3838
3839 elif option=='reconstruction_name':
3840 current_type = 'reconstruction'
3841 current_name = value
3842 if current_name in self[current_type]:
3843 raise InvalidMadAnalysis5Card(
3844 "Reconstruction '%s' already defined in MadAnalysis5 hadron card"%current_name)
3845 else:
3846 self[current_type][current_name] = MadAnalysis5Card.empty_reconstruction()
3847
3848 elif option=='reco_output':
3849 if current_type!='reconstruction' or current_name not in \
3850 self['reconstruction']:
3851 raise InvalidMadAnalysis5Card(
3852 "Option '%s' is only available within the definition of a reconstruction"%option)
3853 if not value.lower() in ['lhe','root']:
3854 raise InvalidMadAnalysis5Card(
3855 "Option '%s' can only take the values 'lhe' or 'root'"%option)
3856 self['reconstruction'][current_name]['reco_output'] = value.lower()
3857
3858 elif option.startswith('recasting'):
3859 current_type = 'recasting'
3860 try:
3861 current_name = option.split('_')[1]
3862 except:
3863 raise InvalidMadAnalysis5Card('Malformed MA5 recasting option %s.'%option)
3864 if len(self['recasting'][current_name])>0:
3865 raise InvalidMadAnalysis5Card(
3866 "Only one recasting can be defined in MadAnalysis5 hadron card")
3867
3868 else:
3869 raise InvalidMadAnalysis5Card(
3870 "Unreckognized MG5aMC instruction in MadAnalysis5 card: '%s'"%option)
3871
3872 if option in ['analysis_name','reconstruction_name'] or \
3873 option.startswith('recasting'):
3874 self['order'].append((current_type,current_name))
3875 continue
3876
3877
3878
3879 if current_name == 'default' and current_type == 'analyses' and\
3880 'default' not in self['analyses']:
3881 self['analyses']['default'] = MadAnalysis5Card.empty_analysis()
3882 self['order'].append(('analyses','default'))
3883
3884 if current_type in ['recasting']:
3885 self[current_type][current_name].append(line)
3886 elif current_type in ['reconstruction']:
3887 self[current_type][current_name]['commands'].append(line)
3888 elif current_type in ['analyses']:
3889 self[current_type][current_name]['commands'].append(line)
3890
3891 if 'reconstruction' in self['analyses'] or len(self['recasting']['card'])>0:
3892 if mode=='parton':
3893 raise InvalidMadAnalysis5Card(
3894 "A parton MadAnalysis5 card cannot specify a recombination or recasting.")
3895 card_mode = 'hadron'
3896 elif mode is None:
3897 card_mode = 'parton'
3898
3899 self['mode'] = card_mode
3900 if self['inputs'] == []:
3901 if self['mode']=='hadron':
3902 self['inputs'] = self._default_hadron_inputs
3903 else:
3904 self['inputs'] = self._default_parton_inputs
3905
3906
3907
3908 if self['mode']=='hadron':
3909 for analysis_name, analysis in self['analyses'].items():
3910 if len(analysis['reconstructions'])==0:
3911 raise InvalidMadAnalysis5Card('Hadron-level analysis '+\
3912 "'%s' is not specified any reconstruction(s)."%analysis_name)
3913 if any(reco not in self['reconstruction'] for reco in \
3914 analysis['reconstructions']):
3915 raise InvalidMadAnalysis5Card('A reconstructions specified in'+\
3916 " analysis '%s' is not defined."%analysis_name)
3917
3918 - def write(self, output):
3919 """ Write an MA5 card."""
3920
3921 if isinstance(output, (file, StringIO.StringIO)):
3922 output_stream = output
3923 elif isinstance(output, str):
3924 output_stream = open(output,'w')
3925 else:
3926 raise MadGraph5Error('Incorrect input for the write function of'+\
3927 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(output)))
3928
3929 output_lines = []
3930 if self._skip_analysis:
3931 output_lines.append('%s skip_analysis'%self._MG5aMC_escape_tag)
3932 output_lines.append('%s inputs = %s'%(self._MG5aMC_escape_tag,','.join(self['inputs'])))
3933 if not self['stdout_lvl'] is None:
3934 output_lines.append('%s stdout_lvl=%s'%(self._MG5aMC_escape_tag,self['stdout_lvl']))
3935 for definition_type, name in self['order']:
3936
3937 if definition_type=='analyses':
3938 output_lines.append('%s analysis_name = %s'%(self._MG5aMC_escape_tag,name))
3939 output_lines.append('%s set_reconstructions = %s'%(self._MG5aMC_escape_tag,
3940 str(self['analyses'][name]['reconstructions'])))
3941 elif definition_type=='reconstruction':
3942 output_lines.append('%s reconstruction_name = %s'%(self._MG5aMC_escape_tag,name))
3943 elif definition_type=='recasting':
3944 output_lines.append('%s recasting_%s'%(self._MG5aMC_escape_tag,name))
3945
3946 if definition_type in ['recasting']:
3947 output_lines.extend(self[definition_type][name])
3948 elif definition_type in ['reconstruction']:
3949 output_lines.append('%s reco_output = %s'%(self._MG5aMC_escape_tag,
3950 self[definition_type][name]['reco_output']))
3951 output_lines.extend(self[definition_type][name]['commands'])
3952 elif definition_type in ['analyses']:
3953 output_lines.extend(self[definition_type][name]['commands'])
3954
3955 output_stream.write('\n'.join(output_lines))
3956
3957 return
3958
3959 - def get_MA5_cmds(self, inputs_arg, submit_folder, run_dir_path=None,
3960 UFO_model_path=None, run_tag=''):
3961 """ Returns a list of tuples ('AnalysisTag',['commands']) specifying
3962 the commands of the MadAnalysis runs required from this card.
3963 At parton-level, the number of such commands is the number of analysis
3964 asked for. In the future, the idea is that the entire card can be
3965 processed in one go from MA5 directly."""
3966
3967 if isinstance(inputs_arg, list):
3968 inputs = inputs_arg
3969 elif isinstance(inputs_arg, str):
3970 inputs = [inputs_arg]
3971 else:
3972 raise MadGraph5Error("The function 'get_MA5_cmds' can only take "+\
3973 " a string or a list for the argument 'inputs_arg'")
3974
3975 if len(inputs)==0:
3976 raise MadGraph5Error("The function 'get_MA5_cmds' must have "+\
3977 " at least one input specified'")
3978
3979 if run_dir_path is None:
3980 run_dir_path = os.path.dirname(inputs_arg)
3981
3982 cmds_list = []
3983
3984 UFO_load = []
3985
3986 if UFO_model_path:
3987 UFO_load.append('import %s'%UFO_model_path)
3988
3989 def get_import(input, type=None):
3990 """ Generates the MA5 import commands for that event file. """
3991 dataset_name = os.path.basename(input).split('.')[0]
3992 res = ['import %s as %s'%(input, dataset_name)]
3993 if not type is None:
3994 res.append('set %s.type = %s'%(dataset_name, type))
3995 return res
3996
3997 fifo_status = {'warned_fifo':False,'fifo_used_up':False}
3998 def warn_fifo(input):
3999 if not input.endswith('.fifo'):
4000 return False
4001 if not fifo_status['fifo_used_up']:
4002 fifo_status['fifo_used_up'] = True
4003 return False
4004 else:
4005 if not fifo_status['warned_fifo']:
4006 logger.warning('Only the first MA5 analysis/reconstructions can be run on a fifo. Subsequent runs will skip fifo inputs.')
4007 fifo_status['warned_fifo'] = True
4008 return True
4009
4010
4011 inputs_load = []
4012 for input in inputs:
4013 inputs_load.extend(get_import(input))
4014
4015 submit_command = 'submit %s'%submit_folder+'_%s'
4016
4017
4018
4019
4020 reconstruction_outputs = {
4021 'lhco_input':[f for f in inputs if
4022 f.endswith('.lhco') or f.endswith('.lhco.gz')],
4023 'root_input':[f for f in inputs if
4024 f.endswith('.root') or f.endswith('.root.gz')]}
4025
4026
4027 recasting_card_path = pjoin(run_dir_path,
4028 '_'.join([run_tag,os.path.basename(submit_folder),'recasting_card.dat']))
4029
4030
4031 for definition_type, name in self['order']:
4032 if definition_type == 'reconstruction':
4033 analysis_cmds = list(self['reconstruction'][name]['commands'])
4034 reco_outputs = []
4035 for i_input, input in enumerate(inputs):
4036
4037 if not MadAnalysis5Card.events_can_be_reconstructed(input):
4038 continue
4039
4040 if warn_fifo(input):
4041 continue
4042 analysis_cmds.append('import %s as reco_events'%input)
4043 if self['reconstruction'][name]['reco_output']=='lhe':
4044 reco_outputs.append('%s_%s.lhe.gz'%(os.path.basename(
4045 input).replace('_events','').split('.')[0],name))
4046 analysis_cmds.append('set main.outputfile=%s'%reco_outputs[-1])
4047 elif self['reconstruction'][name]['reco_output']=='root':
4048 reco_outputs.append('%s_%s.root'%(os.path.basename(
4049 input).replace('_events','').split('.')[0],name))
4050 analysis_cmds.append('set main.fastsim.rootfile=%s'%reco_outputs[-1])
4051 analysis_cmds.append(
4052 submit_command%('reco_%s_%d'%(name,i_input+1)))
4053 analysis_cmds.append('remove reco_events')
4054
4055 reconstruction_outputs[name]= [pjoin(run_dir_path,rec_out)
4056 for rec_out in reco_outputs]
4057 if len(reco_outputs)>0:
4058 cmds_list.append(('_reco_%s'%name,analysis_cmds))
4059
4060 elif definition_type == 'analyses':
4061 if self['mode']=='parton':
4062 cmds_list.append( (name, UFO_load+inputs_load+
4063 self['analyses'][name]['commands']+[submit_command%name]) )
4064 elif self['mode']=='hadron':
4065
4066 for reco in self['analyses'][name]['reconstructions']+\
4067 ['lhco_input','root_input']:
4068 if len(reconstruction_outputs[reco])==0:
4069 continue
4070 if self['reconstruction'][reco]['reco_output']=='lhe':
4071
4072 analysis_cmds = ['set main.mode = parton']
4073 else:
4074 analysis_cmds = []
4075 analysis_cmds.extend(sum([get_import(rec_out) for
4076 rec_out in reconstruction_outputs[reco]],[]))
4077 analysis_cmds.extend(self['analyses'][name]['commands'])
4078 analysis_cmds.append(submit_command%('%s_%s'%(name,reco)))
4079 cmds_list.append( ('%s_%s'%(name,reco),analysis_cmds) )
4080
4081 elif definition_type == 'recasting':
4082 if len(self['recasting']['card'])==0:
4083 continue
4084 if name == 'card':
4085
4086 open(recasting_card_path,'w').write('\n'.join(self['recasting']['card']))
4087 if name == 'commands':
4088 recasting_cmds = list(self['recasting']['commands'])
4089
4090 n_inputs = 0
4091 for input in inputs:
4092 if not MadAnalysis5Card.events_can_be_reconstructed(input):
4093 continue
4094
4095 if warn_fifo(input):
4096 continue
4097 recasting_cmds.extend(get_import(input,'signal'))
4098 n_inputs += 1
4099
4100 recasting_cmds.append('set main.recast.card_path=%s'%recasting_card_path)
4101 recasting_cmds.append(submit_command%'Recasting')
4102 if n_inputs>0:
4103 cmds_list.append( ('Recasting',recasting_cmds))
4104
4105 return cmds_list
4106
4108 """A class object for the run_card for a (aMC@)NLO pocess"""
4109
4110 LO = False
4111
4113 """define the default value"""
4114
4115 self.add_param('run_tag', 'tag_1', include=False)
4116 self.add_param('nevents', 10000)
4117 self.add_param('req_acc', -1.0, include=False)
4118 self.add_param('nevt_job', -1, include=False)
4119 self.add_param('event_norm', 'average')
4120
4121 self.add_param('req_acc_fo', 0.01, include=False)
4122 self.add_param('npoints_fo_grid', 5000, include=False)
4123 self.add_param('niters_fo_grid', 4, include=False)
4124 self.add_param('npoints_fo', 10000, include=False)
4125 self.add_param('niters_fo', 6, include=False)
4126
4127 self.add_param('iseed', 0)
4128 self.add_param('lpp1', 1, fortran_name='lpp(1)')
4129 self.add_param('lpp2', 1, fortran_name='lpp(2)')
4130 self.add_param('ebeam1', 6500.0, fortran_name='ebeam(1)')
4131 self.add_param('ebeam2', 6500.0, fortran_name='ebeam(2)')
4132 self.add_param('pdlabel', 'nn23nlo', allowed=['lhapdf', 'cteq6_m','cteq6_d','cteq6_l','cteq6l1', 'nn23lo','nn23lo1','nn23nlo'])
4133 self.add_param('lhaid', [244600],fortran_name='lhaPDFid')
4134 self.add_param('lhapdfsetname', ['internal_use_only'], system=True)
4135
4136 self.add_param('parton_shower', 'HERWIG6', fortran_name='shower_mc')
4137 self.add_param('shower_scale_factor',1.0)
4138 self.add_param('fixed_ren_scale', False)
4139 self.add_param('fixed_fac_scale', False)
4140 self.add_param('mur_ref_fixed', 91.118)
4141 self.add_param('muf1_ref_fixed', -1.0, hidden=True)
4142 self.add_param('muf_ref_fixed', 91.118)
4143 self.add_param('muf2_ref_fixed', -1.0, hidden=True)
4144 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")
4145 self.add_param('fixed_qes_scale', False, hidden=True)
4146 self.add_param('qes_ref_fixed', -1.0, hidden=True)
4147 self.add_param('mur_over_ref', 1.0)
4148 self.add_param('muf_over_ref', 1.0)
4149 self.add_param('muf1_over_ref', -1.0, hidden=True)
4150 self.add_param('muf2_over_ref', -1.0, hidden=True)
4151 self.add_param('qes_over_ref', -1.0, hidden=True)
4152 self.add_param('reweight_scale', [True], fortran_name='lscalevar')
4153 self.add_param('rw_rscale_down', -1.0, hidden=True)
4154 self.add_param('rw_rscale_up', -1.0, hidden=True)
4155 self.add_param('rw_fscale_down', -1.0, hidden=True)
4156 self.add_param('rw_fscale_up', -1.0, hidden=True)
4157 self.add_param('rw_rscale', [1.0,2.0,0.5], fortran_name='scalevarR')
4158 self.add_param('rw_fscale', [1.0,2.0,0.5], fortran_name='scalevarF')
4159 self.add_param('reweight_pdf', [False], fortran_name='lpdfvar')
4160 self.add_param('pdf_set_min', 244601, hidden=True)
4161 self.add_param('pdf_set_max', 244700, hidden=True)
4162 self.add_param('store_rwgt_info', False)
4163 self.add_param('systematics_program', 'none', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics')
4164 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.')
4165
4166
4167 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]")
4168 self.add_param('bwcutoff', 15.0)
4169
4170 self.add_param('jetalgo', 1.0)
4171 self.add_param('jetradius', 0.7)
4172 self.add_param('ptj', 10.0 , cut=True)
4173 self.add_param('etaj', -1.0, cut=True)
4174 self.add_param('ptl', 0.0, cut=True)
4175 self.add_param('etal', -1.0, cut=True)
4176 self.add_param('drll', 0.0, cut=True)
4177 self.add_param('drll_sf', 0.0, cut=True)
4178 self.add_param('mll', 0.0, cut=True)
4179 self.add_param('mll_sf', 30.0, cut=True)
4180 self.add_param('ptgmin', 20.0, cut=True)
4181 self.add_param('etagamma', -1.0)
4182 self.add_param('r0gamma', 0.4)
4183 self.add_param('xn', 1.0)
4184 self.add_param('epsgamma', 1.0)
4185 self.add_param('isoem', True)
4186 self.add_param('maxjetflavor', 4, hidden=True)
4187 self.add_param('iappl', 0)
4188 self.add_param('lhe_version', 3, hidden=True, include=False)
4189
4190
4191 self.add_param('FO_LHE_weight_ratio',1e-3, hidden=True, system=True)
4192 self.add_param('FO_LHE_postprocessing',['grouping','random'],
4193 hidden=True, system=True, include=False)
4194
4195
4196 self.add_param('pt_min_pdg',{'__type__':0.}, include=False,cut=True)
4197 self.add_param('pt_max_pdg',{'__type__':0.}, include=False,cut=True)
4198 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True)
4199 self.add_param('mxx_only_part_antipart', {'default':False}, include=False, hidden=True)
4200
4201
4202 self.add_param('pdg_cut',[0], hidden=True, system=True)
4203 self.add_param('ptmin4pdg',[0.], hidden=True, system=True)
4204 self.add_param('ptmax4pdg',[-1.], hidden=True, system=True)
4205 self.add_param('mxxmin4pdg',[0.], hidden=True, system=True)
4206 self.add_param('mxxpart_antipart', [False], hidden=True, system=True)
4207
4209 """check the validity of the various input"""
4210
4211 super(RunCardNLO, self).check_validity()
4212
4213
4214 if abs(self['lpp1'])!=1 or abs(self['lpp2'])!=1:
4215 if self['lpp1'] == 1 or self['lpp2']==1:
4216 raise InvalidRunCard('Process like Deep Inelastic scattering not supported at NLO accuracy.')
4217
4218 if self['pdlabel']!='nn23nlo' or self['reweight_pdf']:
4219 self['pdlabel']='nn23nlo'
4220 self['reweight_pdf']=[False]
4221 logger.info('''Lepton-lepton collisions: ignoring PDF related parameters in the run_card.dat (pdlabel, lhaid, reweight_pdf, ...)''')
4222
4223
4224 if self['ickkw'] == 3:
4225
4226 scales=['fixed_ren_scale','fixed_fac_scale','fixed_QES_scale']
4227 for scale in scales:
4228 if self[scale]:
4229 logger.warning('''For consistency in the FxFx merging, \'%s\' has been set to false'''
4230 % scale,'$MG:BOLD')
4231 self[scale]= False
4232
4233 if len(self["dynamical_scale_choice"]) > 1 or self["dynamical_scale_choice"][0] != -1:
4234 self["dynamical_scale_choice"] = [-1]
4235 self["reweight_scale"]=[self["reweight_scale"][0]]
4236 logger.warning('''For consistency in the FxFx merging, dynamical_scale_choice has been set to -1 (default)'''
4237 ,'$MG:BOLD')
4238
4239
4240 jetparams=['jetradius','jetalgo']
4241 for jetparam in jetparams:
4242 if float(self[jetparam]) != 1.0:
4243 logger.info('''For consistency in the FxFx merging, \'%s\' has been set to 1.0'''
4244 % jetparam ,'$MG:BOLD')
4245 self[jetparam] = 1.0
4246 elif self['ickkw'] == -1 and (self["dynamical_scale_choice"][0] != -1 or
4247 len(self["dynamical_scale_choice"]) > 1):
4248 self["dynamical_scale_choice"] = [-1]
4249 self["reweight_scale"]=[self["reweight_scale"][0]]
4250 logger.warning('''For consistency with the jet veto, the scale which will be used is ptj. dynamical_scale_choice will be set at -1.'''
4251 ,'$MG:BOLD')
4252
4253
4254 if self['iappl'] != 0 and self['pdlabel'].lower() != 'lhapdf':
4255 raise InvalidRunCard('APPLgrid generation only possible with the use of LHAPDF')
4256 if self['iappl'] != 0 and not self['reweight_scale']:
4257 raise InvalidRunCard('APPLgrid generation only possible with including' +\
4258 ' the reweighting to get scale dependence')
4259
4260
4261 if self['qes_ref_fixed'] == -1.0:
4262 self['qes_ref_fixed']=self['mur_ref_fixed']
4263 if self['qes_over_ref'] == -1.0:
4264 self['qes_over_ref']=self['mur_over_ref']
4265 if self['muf1_over_ref'] != -1.0 and self['muf1_over_ref'] == self['muf2_over_ref']:
4266 self['muf_over_ref']=self['muf1_over_ref']
4267 if self['muf1_over_ref'] == -1.0:
4268 self['muf1_over_ref']=self['muf_over_ref']
4269 if self['muf2_over_ref'] == -1.0:
4270 self['muf2_over_ref']=self['muf_over_ref']
4271 if self['muf1_ref_fixed'] != -1.0 and self['muf1_ref_fixed'] == self['muf2_ref_fixed']:
4272 self['muf_ref_fixed']=self['muf1_ref_fixed']
4273 if self['muf1_ref_fixed'] == -1.0:
4274 self['muf1_ref_fixed']=self['muf_ref_fixed']
4275 if self['muf2_ref_fixed'] == -1.0:
4276 self['muf2_ref_fixed']=self['muf_ref_fixed']
4277
4278 if (self['rw_rscale_down'] != -1.0 and ['rw_rscale_down'] not in self['rw_rscale']) or\
4279 (self['rw_rscale_up'] != -1.0 and ['rw_rscale_up'] not in self['rw_rscale']):
4280 self['rw_rscale']=[1.0,self['rw_rscale_up'],self['rw_rscale_down']]
4281 if (self['rw_fscale_down'] != -1.0 and ['rw_fscale_down'] not in self['rw_fscale']) or\
4282 (self['rw_fscale_up'] != -1.0 and ['rw_fscale_up'] not in self['rw_fscale']):
4283 self['rw_fscale']=[1.0,self['rw_fscale_up'],self['rw_fscale_down']]
4284
4285
4286 if any(self['reweight_pdf']):
4287
4288 if self['pdlabel'] != "lhapdf":
4289 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.')
4290
4291
4292 if self['pdlabel'] != "lhapdf":
4293 self['reweight_pdf']=[self['reweight_pdf'][0]]
4294 self['lhaid']=[self['lhaid'][0]]
4295
4296
4297 if self['fixed_ren_scale'] and self['fixed_fac_scale']:
4298 self['reweight_scale']=[self['reweight_scale'][0]]
4299 self['dynamical_scale_choice']=[0]
4300
4301
4302
4303
4304 if len(self['reweight_pdf']) == 1 and len(self['lhaid']) != 1:
4305 self['reweight_pdf']=self['reweight_pdf']*len(self['lhaid'])
4306 logger.warning("Setting 'reweight_pdf' for all 'lhaid' to %s" % self['reweight_pdf'][0])
4307 if len(self['reweight_scale']) == 1 and len(self['dynamical_scale_choice']) != 1:
4308 self['reweight_scale']=self['reweight_scale']*len(self['dynamical_scale_choice'])
4309 logger.warning("Setting 'reweight_scale' for all 'dynamical_scale_choice' to %s" % self['reweight_pdf'][0])
4310
4311
4312 if len(self['lhaid']) != len(set(self['lhaid'])):
4313 raise InvalidRunCard("'lhaid' has two or more identical entries. They have to be all different for the code to work correctly.")
4314 if len(self['dynamical_scale_choice']) != len(set(self['dynamical_scale_choice'])):
4315 raise InvalidRunCard("'dynamical_scale_choice' has two or more identical entries. They have to be all different for the code to work correctly.")
4316
4317
4318 if len(self['reweight_pdf']) != len(self['lhaid']):
4319 raise InvalidRunCard("'reweight_pdf' and 'lhaid' lists should have the same length")
4320 if len(self['reweight_scale']) != len(self['dynamical_scale_choice']):
4321 raise InvalidRunCard("'reweight_scale' and 'dynamical_scale_choice' lists should have the same length")
4322 if len(self['dynamical_scale_choice']) > 10 :
4323 raise InvalidRunCard("Length of list for 'dynamical_scale_choice' too long: max is 10.")
4324 if len(self['lhaid']) > 25 :
4325 raise InvalidRunCard("Length of list for 'lhaid' too long: max is 25.")
4326 if len(self['rw_rscale']) > 9 :
4327 raise InvalidRunCard("Length of list for 'rw_rscale' too long: max is 9.")
4328 if len(self['rw_fscale']) > 9 :
4329 raise InvalidRunCard("Length of list for 'rw_fscale' too long: max is 9.")
4330
4331 if 1.0 not in self['rw_rscale']:
4332 logger.warning("'1.0' has to be part of 'rw_rscale', adding it")
4333 self['rw_rscale'].insert(0,1.0)
4334 if 1.0 not in self['rw_fscale']:
4335 logger.warning("'1.0' has to be part of 'rw_fscale', adding it")
4336 self['rw_fscale'].insert(0,1.0)
4337 if self['rw_rscale'][0] != 1.0 and 1.0 in self['rw_rscale']:
4338 a=self['rw_rscale'].index(1.0)
4339 self['rw_rscale'][0],self['rw_rscale'][a]=self['rw_rscale'][a],self['rw_rscale'][0]
4340 if self['rw_fscale'][0] != 1.0 and 1.0 in self['rw_fscale']:
4341 a=self['rw_fscale'].index(1.0)
4342 self['rw_fscale'][0],self['rw_fscale'][a]=self['rw_fscale'][a],self['rw_fscale'][0]
4343
4344 if len(self['rw_rscale']) != len(set(self['rw_rscale'])):
4345 raise InvalidRunCard("'rw_rscale' has two or more identical entries. They have to be all different for the code to work correctly.")
4346 if len(self['rw_fscale']) != len(set(self['rw_fscale'])):
4347 raise InvalidRunCard("'rw_fscale' has two or more identical entries. They have to be all different for the code to work correctly.")
4348
4349
4350
4351 for i in [1,2]:
4352 if self['lpp%s' % i ] not in [1,2]:
4353 continue
4354
4355 if self['ebeam%i' % i] < 0.938:
4356 if self['ebeam%i' %i] == 0:
4357 logger.warning("At rest proton mode set: Energy beam set to 0.938")
4358 self.set('ebeam%i' %i, 0.938)
4359 else:
4360 raise InvalidRunCard("Energy for beam %i lower than proton mass. Please fix this")
4361
4362
4364
4365
4366 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys())+
4367 list(self['mxx_min_pdg'].keys())+ list(self['mxx_only_part_antipart'].keys()))
4368 pdg_to_cut.discard('__type__')
4369 pdg_to_cut.discard('default')
4370 if len(pdg_to_cut)>25:
4371 raise Exception("Maximum 25 different PDGs are allowed for PDG specific cut")
4372
4373 if any(int(pdg)<0 for pdg in pdg_to_cut):
4374 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
4375 raise MadGraph5Error('Some PDG specific cuts are defined with negative PDG codes')
4376
4377
4378 if any(pdg in pdg_to_cut for pdg in [21,22,11,13,15]+ list(range(self['maxjetflavor']+1))):
4379
4380 raise Exception("Can not use PDG related cuts for massless SM particles/leptons")
4381 if pdg_to_cut:
4382 self['pdg_cut'] = list(pdg_to_cut)
4383 self['ptmin4pdg'] = []
4384 self['ptmax4pdg'] = []
4385 self['mxxmin4pdg'] = []
4386 self['mxxpart_antipart'] = []
4387 for pdg in self['pdg_cut']:
4388 for var in ['pt','mxx']:
4389 for minmax in ['min', 'max']:
4390 if var == 'mxx' and minmax == 'max':
4391 continue
4392 new_var = '%s%s4pdg' % (var, minmax)
4393 old_var = '%s_%s_pdg' % (var, minmax)
4394 default = 0. if minmax=='min' else -1.
4395 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4396
4397 old_var = 'mxx_only_part_antipart'
4398 new_var = 'mxxpart_antipart'
4399 if 'default' in self[old_var]:
4400 default = self[old_var]['default']
4401 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4402 else:
4403 if str(pdg) not in self[old_var]:
4404 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
4405 self[new_var].append(self[old_var][str(pdg)])
4406 else:
4407 self['pdg_cut'] = [0]
4408 self['ptmin4pdg'] = [0.]
4409 self['ptmax4pdg'] = [-1.]
4410 self['mxxmin4pdg'] = [0.]
4411 self['mxxpart_antipart'] = [False]
4412
4413 - def write(self, output_file, template=None, python_template=False, **opt):
4414 """Write the run_card in output_file according to template
4415 (a path to a valid run_card)"""
4416
4417 if not template:
4418 if not MADEVENT:
4419 template = pjoin(MG5DIR, 'Template', 'NLO', 'Cards',
4420 'run_card.dat')
4421 python_template = True
4422 else:
4423 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
4424 python_template = False
4425
4426 super(RunCardNLO, self).write(output_file, template=template,
4427 python_template=python_template, **opt)
4428
4429
4431 """Rules
4432 e+ e- beam -> lpp:0 ebeam:500
4433 p p beam -> set maxjetflavor automatically
4434 """
4435
4436
4437 beam_id = set()
4438 for proc in proc_def:
4439 for leg in proc['legs']:
4440 if not leg['state']:
4441 beam_id.add(leg['id'])
4442 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
4443 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
4444 self['maxjetflavor'] = maxjetflavor
4445 pass
4446 elif any(id in beam_id for id in [11,-11,13,-13]):
4447 self['lpp1'] = 0
4448 self['lpp2'] = 0
4449 self['ebeam1'] = 500
4450 self['ebeam2'] = 500
4451 else:
4452 self['lpp1'] = 0
4453 self['lpp2'] = 0
4454
4455 if proc_characteristic['ninitial'] == 1:
4456
4457 self.remove_all_cut()
4458
4459
4460 min_particle = 99
4461 max_particle = 0
4462 for proc in proc_def:
4463 min_particle = min(len(proc['legs']), min_particle)
4464 max_particle = max(len(proc['legs']), max_particle)
4465 matching = False
4466 if min_particle != max_particle:
4467
4468 for procmin in proc_def:
4469 if len(procmin['legs']) != min_particle:
4470 continue
4471 else:
4472 idsmin = [l['id'] for l in procmin['legs']]
4473 break
4474
4475 for procmax in proc_def:
4476 if len(procmax['legs']) != max_particle:
4477 continue
4478 idsmax = [l['id'] for l in procmax['legs']]
4479 for i in idsmin:
4480 if i not in idsmax:
4481 continue
4482 else:
4483 idsmax.remove(i)
4484 for j in idsmax:
4485 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
4486 break
4487 else:
4488
4489 matching=True
4490 break
4491
4492 if matching:
4493 self['ickkw'] = 3
4494 self['fixed_ren_scale'] = False
4495 self["fixed_fac_scale"] = False
4496 self["fixed_QES_scale"] = False
4497 self["jetalgo"] = 1
4498 self["jetradius"] = 1
4499 self["parton_shower"] = "PYTHIA8"
4500
4505 """ a class for storing/dealing with the file MadLoopParam.dat
4506 contains a parser to read it, facilities to write a new file,...
4507 """
4508
4509 _ID_reduction_tool_map = {1:'CutTools',
4510 2:'PJFry++',
4511 3:'IREGI',
4512 4:'Golem95',
4513 5:'Samurai',
4514 6:'Ninja',
4515 7:'COLLIER'}
4516
4518 """initialize the directory to the default value"""
4519
4520 self.add_param("MLReductionLib", "6|7|1")
4521 self.add_param("IREGIMODE", 2)
4522 self.add_param("IREGIRECY", True)
4523 self.add_param("CTModeRun", -1)
4524 self.add_param("MLStabThres", 1e-3)
4525 self.add_param("NRotations_DP", 0)
4526 self.add_param("NRotations_QP", 0)
4527 self.add_param("ImprovePSPoint", 2)
4528 self.add_param("CTLoopLibrary", 2)
4529 self.add_param("CTStabThres", 1e-2)
4530 self.add_param("CTModeInit", 1)
4531 self.add_param("CheckCycle", 3)
4532 self.add_param("MaxAttempts", 10)
4533 self.add_param("ZeroThres", 1e-9)
4534 self.add_param("OSThres", 1.0e-8)
4535 self.add_param("DoubleCheckHelicityFilter", True)
4536 self.add_param("WriteOutFilters", True)
4537 self.add_param("UseLoopFilter", False)
4538 self.add_param("HelicityFilterLevel", 2)
4539 self.add_param("LoopInitStartOver", False)
4540 self.add_param("HelInitStartOver", False)
4541 self.add_param("UseQPIntegrandForNinja", True)
4542 self.add_param("UseQPIntegrandForCutTools", True)
4543 self.add_param("COLLIERMode", 1)
4544 self.add_param("COLLIERComputeUVpoles", True)
4545 self.add_param("COLLIERComputeIRpoles", True)
4546 self.add_param("COLLIERRequiredAccuracy", 1.0e-8)
4547 self.add_param("COLLIERCanOutput",False)
4548 self.add_param("COLLIERGlobalCache",-1)
4549 self.add_param("COLLIERUseCacheForPoles",False)
4550 self.add_param("COLLIERUseInternalStabilityTest",True)
4551
4552 - def read(self, finput):
4553 """Read the input file, this can be a path to a file,
4554 a file object, a str with the content of the file."""
4555
4556 if isinstance(finput, str):
4557 if "\n" in finput:
4558 finput = finput.split('\n')
4559 elif os.path.isfile(finput):
4560 finput = open(finput)
4561 else:
4562 raise Exception("No such file %s" % input)
4563
4564 previous_line= ''
4565 for line in finput:
4566 if previous_line.startswith('#'):
4567 name = previous_line[1:].split()[0]
4568 value = line.strip()
4569 if len(value) and value[0] not in ['#', '!']:
4570 self.__setitem__(name, value, change_userdefine=True)
4571 previous_line = line
4572
4573
4574 - def write(self, outputpath, template=None,commentdefault=False):
4575
4576 if not template:
4577 if not MADEVENT:
4578 template = pjoin(MG5DIR, 'Template', 'loop_material', 'StandAlone',
4579 'Cards', 'MadLoopParams.dat')
4580 else:
4581 template = pjoin(MEDIR, 'Cards', 'MadLoopParams_default.dat')
4582 fsock = open(template, 'r')
4583 template = fsock.readlines()
4584 fsock.close()
4585
4586 if isinstance(outputpath, str):
4587 output = open(outputpath, 'w')
4588 else:
4589 output = outputpath
4590
4591 def f77format(value):
4592 if isinstance(value, bool):
4593 if value:
4594 return '.true.'
4595 else:
4596 return '.false.'
4597 elif isinstance(value, int):
4598 return value
4599 elif isinstance(value, float):
4600 tmp ='%e' % value
4601 return tmp.replace('e','d')
4602 elif isinstance(value, str):
4603 return value
4604 else:
4605 raise Exception("Can not format input %s" % type(value))
4606
4607 name = ''
4608 done = set()
4609 for line in template:
4610 if name:
4611 done.add(name)
4612 if commentdefault and name.lower() not in self.user_set :
4613 output.write('!%s\n' % f77format(self[name]))
4614 else:
4615 output.write('%s\n' % f77format(self[name]))
4616 name=''
4617 continue
4618 elif line.startswith('#'):
4619 name = line[1:].split()[0]
4620 output.write(line)
4621