1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 from __future__ import division
17 from __future__ import absolute_import
18 import collections
19 import copy
20 import logging
21 import numbers
22 import os
23 import sys
24 import re
25 import math
26 import six
27 StringIO = six
28 from six.moves import range
29 if six.PY3:
30 import io
31 file = io.IOBase
32 import itertools
33 import time
34
35
36 pjoin = os.path.join
37
38 try:
39 import madgraph
40 except ImportError:
41 MADEVENT = True
42 from internal import MadGraph5Error, InvalidCmd
43 import internal.file_writers as file_writers
44 import internal.files as files
45 import internal.check_param_card as param_card_reader
46 import internal.misc as misc
47 MEDIR = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
48 MEDIR = os.path.split(MEDIR)[0]
49 else:
50 MADEVENT = False
51 import madgraph.various.misc as misc
52 import madgraph.iolibs.file_writers as file_writers
53 import madgraph.iolibs.files as files
54 import models.check_param_card as param_card_reader
55 from madgraph import MG5DIR, MadGraph5Error, InvalidCmd
56
57
58
59 logger = logging.getLogger('madevent.cards')
64
67 """ """
68
69 ordered_items = ['mgversion', 'mg5proccard', 'mgproccard', 'mgruncard',
70 'slha','initrwgt','mggenerationinfo', 'mgpythiacard', 'mgpgscard',
71 'mgdelphescard', 'mgdelphestrigger','mgshowercard',
72 'ma5card_parton','ma5card_hadron','run_settings']
73
74 capitalized_items = {
75 'mgversion': 'MGVersion',
76 'mg5proccard': 'MG5ProcCard',
77 'mgproccard': 'MGProcCard',
78 'mgruncard': 'MGRunCard',
79 'ma5card_parton' : 'MA5Card_parton',
80 'ma5card_hadron' : 'MA5Card_hadron',
81 'mggenerationinfo': 'MGGenerationInfo',
82 'mgpythiacard': 'MGPythiaCard',
83 'mgpgscard': 'MGPGSCard',
84 'mgdelphescard': 'MGDelphesCard',
85 'mgdelphestrigger': 'MGDelphesTrigger',
86 'mgshowercard': 'MGShowerCard' }
87
88 forbid_cdata = ['initrwgt']
89
91 """ """
92
93 if isinstance(banner_path, Banner):
94 dict.__init__(self, banner_path)
95 self.lhe_version = banner_path.lhe_version
96 return
97 else:
98 dict.__init__(self)
99
100
101 if MADEVENT:
102 self['mgversion'] = '#%s\n' % open(pjoin(MEDIR, 'MGMEVersion.txt')).read()
103 else:
104 info = misc.get_pkg_info()
105 self['mgversion'] = info['version']+'\n'
106
107 self.lhe_version = None
108
109
110 if banner_path:
111 self.read_banner(banner_path)
112
113
114
115
116 pat_begin=re.compile('<(?P<name>\w*)>')
117 pat_end=re.compile('</(?P<name>\w*)>')
118
119 tag_to_file={'slha':'param_card.dat',
120 'mgruncard':'run_card.dat',
121 'mgpythiacard':'pythia_card.dat',
122 'mgpgscard' : 'pgs_card.dat',
123 'mgdelphescard':'delphes_card.dat',
124 'mgdelphestrigger':'delphes_trigger.dat',
125 'mg5proccard':'proc_card_mg5.dat',
126 'mgproccard': 'proc_card.dat',
127 'init': '',
128 'mggenerationinfo':'',
129 'scalesfunctionalform':'',
130 'montecarlomasses':'',
131 'initrwgt':'',
132 'madspin':'madspin_card.dat',
133 'mgshowercard':'shower_card.dat',
134 'pythia8':'pythia8_card.dat',
135 'ma5card_parton':'madanalysis5_parton_card.dat',
136 'ma5card_hadron':'madanalysis5_hadron_card.dat',
137 'run_settings':''
138 }
139
141 """read a banner"""
142
143 if isinstance(input_path, str):
144 if input_path.find('\n') ==-1:
145 input_path = open(input_path)
146 else:
147 def split_iter(string):
148 return (x.groups(0)[0] for x in re.finditer(r"([^\n]*\n)", string, re.DOTALL))
149 input_path = split_iter(input_path)
150
151 text = ''
152 store = False
153 for line in input_path:
154 if self.pat_begin.search(line):
155 if self.pat_begin.search(line).group('name').lower() in self.tag_to_file:
156 tag = self.pat_begin.search(line).group('name').lower()
157 store = True
158 continue
159 if store and self.pat_end.search(line):
160 if tag == self.pat_end.search(line).group('name').lower():
161 self[tag] = text
162 text = ''
163 store = False
164 if store and not line.startswith(('<![CDATA[',']]>')):
165 if line.endswith('\n'):
166 text += line
167 else:
168 text += '%s%s' % (line, '\n')
169
170
171 if "</init>" in line:
172 break
173 elif "<event>" in line:
174 break
175
177 """allow auto-build for the run_card/param_card/... """
178 try:
179 return super(Banner, self).__getattribute__(attr)
180 except:
181 if attr not in ['run_card', 'param_card', 'slha', 'mgruncard', 'mg5proccard', 'mgshowercard', 'foanalyse']:
182 raise
183 return self.charge_card(attr)
184
185
186
188 """change the lhe version associate to the banner"""
189
190 version = float(version)
191 if version < 3:
192 version = 1
193 elif version > 3:
194 raise Exception("Not Supported version")
195 self.lhe_version = version
196
198 """return the cross-section of the file"""
199
200 if "init" not in self:
201 raise Exception
202
203 text = self["init"].split('\n')
204 cross = 0
205 error = 0
206 for line in text:
207 s = line.split()
208 if len(s)==4:
209 cross += float(s[0])
210 if witherror:
211 error += float(s[1])**2
212 if not witherror:
213 return cross
214 else:
215 return cross, math.sqrt(error)
216
217
219 """modify the init information with the associate scale"""
220
221 assert "init" in self
222
223 all_lines = self["init"].split('\n')
224 new_data = []
225 new_data.append(all_lines[0])
226 for i in range(1, len(all_lines)):
227 line = all_lines[i]
228 split = line.split()
229 if len(split) == 4:
230 xsec, xerr, xmax, pid = split
231 else:
232 new_data += all_lines[i:]
233 break
234 pid = int(pid)
235
236 line = " %+13.7e %+13.7e %+13.7e %i" % \
237 (ratio*float(xsec), ratio* float(xerr), ratio*float(xmax), pid)
238 new_data.append(line)
239 self['init'] = '\n'.join(new_data)
240
242 """return the pdg of each beam"""
243
244 assert "init" in self
245
246 all_lines = self["init"].split('\n')
247 pdg1,pdg2,_ = all_lines[0].split(None, 2)
248 return int(pdg1), int(pdg2)
249
251 """ Load the proc_card /param_card and run_card """
252
253 self.add(pjoin(medir,'Cards', 'param_card.dat'))
254 self.add(pjoin(medir,'Cards', 'run_card.dat'))
255 if os.path.exists(pjoin(medir, 'SubProcesses', 'procdef_mg5.dat')):
256 self.add(pjoin(medir,'SubProcesses', 'procdef_mg5.dat'))
257 self.add(pjoin(medir,'Cards', 'proc_card_mg5.dat'))
258 else:
259 self.add(pjoin(medir,'Cards', 'proc_card.dat'))
260
262 """Change the seed value in the banner"""
263
264 p = re.compile(r'''^\s*\d+\s*=\s*iseed''', re.M)
265 new_seed_str = " %s = iseed" % seed
266 self['mgruncard'] = p.sub(new_seed_str, self['mgruncard'])
267
269 """add info on MGGeneration"""
270
271 text = """
272 # Number of Events : %s
273 # Integrated weight (pb) : %s
274 """ % (nb_event, cross)
275 self['MGGenerationInfo'] = text
276
277
278
279
280 - def split(self, me_dir, proc_card=True):
281 """write the banner in the Cards directory.
282 proc_card argument is present to avoid the overwrite of proc_card
283 information"""
284
285 for tag, text in self.items():
286 if tag == 'mgversion':
287 continue
288 if not proc_card and tag in ['mg5proccard','mgproccard']:
289 continue
290 if not self.tag_to_file[tag]:
291 continue
292 ff = open(pjoin(me_dir, 'Cards', self.tag_to_file[tag]), 'w')
293 ff.write(text)
294 ff.close()
295
296
297
298
299
301 """special routine removing width/mass of particles not present in the model
302 This is usefull in case of loop model card, when we want to use the non
303 loop model."""
304
305 if not hasattr(self, 'param_card'):
306 self.charge_card('slha')
307
308 for tag in ['mass', 'decay']:
309 block = self.param_card.get(tag)
310 for data in block:
311 pid = data.lhacode[0]
312 if pid not in list(pid2label.keys()):
313 block.remove((pid,))
314
316 """get the lha_strategy: how the weight have to be handle by the shower"""
317
318 if not self["init"]:
319 raise Exception("No init block define")
320
321 data = self["init"].split('\n')[0].split()
322 if len(data) != 10:
323 misc.sprint(len(data), self['init'])
324 raise Exception("init block has a wrong format")
325 return int(float(data[-2]))
326
328 """set the lha_strategy: how the weight have to be handle by the shower"""
329
330 if not (-4 <= int(value) <= 4):
331 six.reraise(Exception, "wrong value for lha_strategy", value)
332 if not self["init"]:
333 raise Exception("No init block define")
334
335 all_lines = self["init"].split('\n')
336 data = all_lines[0].split()
337 if len(data) != 10:
338 misc.sprint(len(data), self['init'])
339 raise Exception("init block has a wrong format")
340 data[-2] = '%s' % value
341 all_lines[0] = ' '.join(data)
342 self['init'] = '\n'.join(all_lines)
343
344
346 """modify the init information with the associate cross-section"""
347 assert isinstance(cross, dict)
348
349 assert "init" in self
350
351 cross = dict(cross)
352 for key in cross.keys():
353 if isinstance(key, str) and key.isdigit() and int(key) not in cross:
354 cross[int(key)] = cross[key]
355
356
357 all_lines = self["init"].split('\n')
358 new_data = []
359 new_data.append(all_lines[0])
360 for i in range(1, len(all_lines)):
361 line = all_lines[i]
362 split = line.split()
363 if len(split) == 4:
364 xsec, xerr, xmax, pid = split
365 else:
366 new_data += all_lines[i:]
367 break
368 if int(pid) not in cross:
369 raise Exception
370 pid = int(pid)
371 if float(xsec):
372 ratio = cross[pid]/float(xsec)
373 else:
374 ratio = 0
375 line = " %+13.7e %+13.7e %+13.7e %i" % \
376 (float(cross[pid]), ratio* float(xerr), ratio*float(xmax), pid)
377 new_data.append(line)
378 self['init'] = '\n'.join(new_data)
379
380
381
382
383 - def write(self, output_path, close_tag=True, exclude=[]):
384 """write the banner"""
385
386 if isinstance(output_path, str):
387 ff = open(output_path, 'w')
388 else:
389 ff = output_path
390
391 if MADEVENT:
392 header = open(pjoin(MEDIR, 'Source', 'banner_header.txt')).read()
393 else:
394 header = open(pjoin(MG5DIR,'Template', 'LO', 'Source', 'banner_header.txt')).read()
395
396 if not self.lhe_version:
397 self.lhe_version = self.get('run_card', 'lhe_version', default=1.0)
398 if float(self.lhe_version) < 3:
399 self.lhe_version = 1.0
400 out = header % { 'version':float(self.lhe_version)}
401 try:
402 ff.write(out)
403 except:
404 ff.write(out.encode('utf-8'))
405
406 for tag in [t for t in self.ordered_items if t in list(self.keys())]+ \
407 [t for t in self.keys() if t not in self.ordered_items]:
408 if tag in ['init'] or tag in exclude:
409 continue
410 capitalized_tag = self.capitalized_items[tag] if tag in self.capitalized_items else tag
411 start_data, stop_data = '', ''
412 if capitalized_tag not in self.forbid_cdata and \
413 ('<' in self[tag] or '@' in self[tag]):
414 start_data = '\n<![CDATA['
415 stop_data = ']]>\n'
416 out = '<%(tag)s>%(start_data)s\n%(text)s\n%(stop_data)s</%(tag)s>\n' % \
417 {'tag':capitalized_tag, 'text':self[tag].strip(),
418 'start_data': start_data, 'stop_data':stop_data}
419 try:
420 ff.write(out)
421 except:
422 ff.write(out.encode('utf-8'))
423
424
425 if not '/header' in exclude:
426 out = '</header>\n'
427 try:
428 ff.write(out)
429 except:
430 ff.write(out.encode('utf-8'))
431
432 if 'init' in self and not 'init' in exclude:
433 text = self['init']
434 out = '<%(tag)s>\n%(text)s\n</%(tag)s>\n' % \
435 {'tag':'init', 'text':text.strip()}
436 try:
437 ff.write(out)
438 except:
439 ff.write(out.encode('utf-8'))
440
441 if close_tag:
442 out = '</LesHouchesEvents>\n'
443 try:
444 ff.write(out)
445 except:
446 ff.write(out.encode('utf-8'))
447 return ff
448
449
450
451
452
453 - def add(self, path, tag=None):
454 """Add the content of the file to the banner"""
455
456 if not tag:
457 card_name = os.path.basename(path)
458 if 'param_card' in card_name:
459 tag = 'slha'
460 elif 'run_card' in card_name:
461 tag = 'MGRunCard'
462 elif 'pythia_card' in card_name:
463 tag = 'MGPythiaCard'
464 elif 'pythia8_card' in card_name or 'pythia8.cmd' in card_name:
465 tag = 'MGPythiaCard'
466 elif 'pgs_card' in card_name:
467 tag = 'MGPGSCard'
468 elif 'delphes_card' in card_name:
469 tag = 'MGDelphesCard'
470 elif 'delphes_trigger' in card_name:
471 tag = 'MGDelphesTrigger'
472 elif 'proc_card_mg5' in card_name:
473 tag = 'MG5ProcCard'
474 elif 'proc_card' in card_name:
475 tag = 'MGProcCard'
476 elif 'procdef_mg5' in card_name:
477 tag = 'MGProcCard'
478 elif 'shower_card' in card_name:
479 tag = 'MGShowerCard'
480 elif 'madspin_card' in card_name:
481 tag = 'madspin'
482 elif 'FO_analyse_card' in card_name:
483 tag = 'foanalyse'
484 elif 'reweight_card' in card_name:
485 tag='reweight_card'
486 elif 'madanalysis5_parton_card' in card_name:
487 tag='MA5Card_parton'
488 elif 'madanalysis5_hadron_card' in card_name:
489 tag='MA5Card_hadron'
490 else:
491 raise Exception('Impossible to know the type of the card')
492
493 self.add_text(tag.lower(), open(path).read())
494
495 - def add_text(self, tag, text):
496 """Add the content of the file to the banner"""
497
498 if tag == 'param_card':
499 tag = 'slha'
500 elif tag == 'run_card':
501 tag = 'mgruncard'
502 elif tag == 'proc_card':
503 tag = 'mg5proccard'
504 elif tag == 'shower_card':
505 tag = 'mgshowercard'
506 elif tag == 'FO_analyse_card':
507 tag = 'foanalyse'
508
509 self[tag.lower()] = text
510
511
561
562
564 """return a specific """
565
566 if tag in ['param_card', 'param']:
567 tag = 'slha'
568 attr_tag = 'param_card'
569 elif tag in ['run_card', 'run']:
570 tag = 'mgruncard'
571 attr_tag = 'run_card'
572 elif tag == 'proc_card':
573 tag = 'mg5proccard'
574 attr_tag = 'proc_card'
575 elif tag == 'model':
576 tag = 'mg5proccard'
577 attr_tag = 'proc_card'
578 arg = ('model',)
579 elif tag == 'generate':
580 tag = 'mg5proccard'
581 attr_tag = 'proc_card'
582 arg = ('generate',)
583 elif tag == 'shower_card':
584 tag = 'mgshowercard'
585 attr_tag = 'shower_card'
586 assert tag in ['slha', 'mgruncard', 'mg5proccard', 'shower_card'], '%s not recognized' % tag
587
588 if not hasattr(self, attr_tag):
589 self.charge_card(attr_tag)
590
591 card = getattr(self, attr_tag)
592 if len(arg) == 0:
593 return card
594 elif len(arg) == 1:
595 if tag == 'mg5proccard':
596 try:
597 return card.get(arg[0])
598 except KeyError as error:
599 if 'default' in opt:
600 return opt['default']
601 else:
602 raise
603 try:
604 return card[arg[0]]
605 except KeyError:
606 if 'default' in opt:
607 return opt['default']
608 else:
609 raise
610 elif len(arg) == 2 and tag == 'slha':
611 try:
612 return card[arg[0]].get(arg[1:])
613 except KeyError:
614 if 'default' in opt:
615 return opt['default']
616 else:
617 raise
618 elif len(arg) == 0:
619 return card
620 else:
621 raise Exception("Unknow command")
622
623
624 get = get_detail
625
626 - def set(self, card, *args):
627 """modify one of the cards"""
628
629 if tag == 'param_card':
630 tag = 'slha'
631 attr_tag = 'param_card'
632 elif tag == 'run_card':
633 tag = 'mgruncard'
634 attr_tag = 'run_card'
635 elif tag == 'proc_card':
636 tag = 'mg5proccard'
637 attr_tag = 'proc_card'
638 elif tag == 'model':
639 tag = 'mg5proccard'
640 attr_tag = 'proc_card'
641 arg = ('model',)
642 elif tag == 'generate':
643 tag = 'mg5proccard'
644 attr_tag = 'proc_card'
645 arg = ('generate',)
646 elif tag == 'shower_card':
647 tag = 'mgshowercard'
648 attr_tag = 'shower_card'
649 assert tag in ['slha', 'mgruncard', 'mg5proccard', 'shower_card'], 'not recognized'
650
651 if not hasattr(self, attr_tag):
652 self.charge_card(attr_tag)
653
654 card = getattr(self, attr_tag)
655 if len(args) ==2:
656 if tag == 'mg5proccard':
657 card.info[args[0]] = args[-1]
658 else:
659 card[args[0]] = args[1]
660 else:
661 card[args[:-1]] = args[-1]
662
663
664 @misc.multiple_try()
666 """Add the banner to a file and change the associate seed in the banner"""
667
668 if seed is not None:
669 self.set("run_card", "iseed", seed)
670
671 if not out:
672 path_out = "%s.tmp" % path
673 else:
674 path_out = out
675
676 ff = self.write(path_out, close_tag=False,
677 exclude=['MGGenerationInfo', '/header', 'init'])
678 ff.write("## END BANNER##\n")
679 if self.lhe_version >= 3:
680
681 [ff.write(line) if not line.startswith("<generator name='MadGraph5_aMC@NLO'")
682 else ff.write("<generator name='MadGraph5_aMC@NLO' version='%s'>" % self['mgversion'][:-1])
683 for line in open(path)]
684 else:
685 [ff.write(line) for line in open(path)]
686 ff.write("</LesHouchesEvents>\n")
687 ff.close()
688 if out:
689 os.remove(path)
690 else:
691 files.mv(path_out, path)
692
693
694
695 -def split_banner(banner_path, me_dir, proc_card=True):
700
702 """as input we receive a gen_crossxhtml.AllResults object.
703 This define the current banner and load it
704 """
705
706 if not run:
707 try:
708 _run = results_object.current['run_name']
709 _tag = results_object.current['tag']
710 except Exception:
711 return Banner()
712 else:
713 _run = run
714 if not tag:
715 try:
716 _tag = results_object[run].tags[-1]
717 except Exception as error:
718 if os.path.exists( pjoin(results_object.path,'Events','%s_banner.txt' % (run))):
719 tag = None
720 else:
721 return Banner()
722 else:
723 _tag = tag
724
725
726 path = results_object.path
727 if tag:
728 banner_path = pjoin(path,'Events',run,'%s_%s_banner.txt' % (run, tag))
729 else:
730 banner_path = pjoin(results_object.path,'Events','%s_banner.txt' % (run))
731
732 if not os.path.exists(banner_path):
733 if level != "parton" and tag != _tag:
734 return recover_banner(results_object, level, _run, results_object[_run].tags[0])
735 elif level == 'parton':
736 paths = [pjoin(path,'Events',run, 'unweighted_events.lhe.gz'),
737 pjoin(path,'Events',run, 'unweighted_events.lhe'),
738 pjoin(path,'Events',run, 'events.lhe.gz'),
739 pjoin(path,'Events',run, 'events.lhe')]
740 for p in paths:
741 if os.path.exists(p):
742 if MADEVENT:
743 import internal.lhe_parser as lhe_parser
744 else:
745 import madgraph.various.lhe_parser as lhe_parser
746 lhe = lhe_parser.EventFile(p)
747 return Banner(lhe.banner)
748
749
750 return Banner()
751
752 banner = Banner(banner_path)
753
754
755
756 if level == 'pythia':
757 if 'mgpythiacard' in banner:
758 del banner['mgpythiacard']
759 if level in ['pythia','pgs','delphes']:
760 for tag in ['mgpgscard', 'mgdelphescard', 'mgdelphestrigger']:
761 if tag in banner:
762 del banner[tag]
763 return banner
764
767
769 """Basic Proccard object"""
770
771 history_header = \
772 '#************************************************************\n' + \
773 '#* MadGraph5_aMC@NLO *\n' + \
774 '#* *\n' + \
775 "#* * * *\n" + \
776 "#* * * * * *\n" + \
777 "#* * * * * 5 * * * * *\n" + \
778 "#* * * * * *\n" + \
779 "#* * * *\n" + \
780 "#* *\n" + \
781 "#* *\n" + \
782 "%(info_line)s" +\
783 "#* *\n" + \
784 "#* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \
785 "#* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
786 '#* *\n' + \
787 '#************************************************************\n' + \
788 '#* *\n' + \
789 '#* Command File for MadGraph5_aMC@NLO *\n' + \
790 '#* *\n' + \
791 '#* run as ./bin/mg5_aMC filename *\n' + \
792 '#* *\n' + \
793 '#************************************************************\n'
794
795
796
797
799 """ initialize a basic proc_card"""
800 self.info = {'model': 'sm', 'generate':None,
801 'full_model_line':'import model sm'}
802 list.__init__(self)
803 if init:
804 self.read(init)
805
806
807 - def read(self, init):
808 """read the proc_card and save the information"""
809
810 if isinstance(init, str):
811 init = open(init, 'r')
812
813 store_line = ''
814 for line in init:
815 line = line.rstrip()
816 if line.endswith('\\'):
817 store_line += line[:-1]
818 else:
819 tmp = store_line + line
820 self.append(tmp.strip())
821 store_line = ""
822 if store_line:
823 raise Exception("WRONG CARD FORMAT")
824
825
827 """move an element to the last history."""
828 for line in self[:]:
829 if line.startswith(cmd):
830 self.remove(line)
831 list.append(self, line)
832
834 """"add a line in the proc_card perform automatically cleaning"""
835
836 line = line.strip()
837 cmds = line.split()
838 if len(cmds) == 0:
839 return
840
841 list.append(self, line)
842
843
844 cmd = cmds[0]
845
846 if cmd == 'output':
847
848 self.clean(allow_for_removal = ['output'], keep_switch=True,
849 remove_bef_last='output')
850 elif cmd == 'generate':
851
852 self.clean(remove_bef_last='generate', keep_switch=True,
853 allow_for_removal= ['generate', 'add process', 'output'])
854 self.info['generate'] = ' '.join(cmds[1:])
855 elif cmd == 'add' and cmds[1] == 'process' and not self.info['generate']:
856 self.info['generate'] = ' '.join(cmds[2:])
857 elif cmd == 'import':
858 if len(cmds) < 2:
859 return
860 if cmds[1].startswith('model'):
861 self.info['full_model_line'] = line
862 self.clean(remove_bef_last='import', keep_switch=True,
863 allow_for_removal=['generate', 'add process', 'add model', 'output'])
864 if cmds[1] == 'model':
865 self.info['model'] = cmds[2]
866 else:
867 self.info['model'] = None
868 elif cmds[1] == 'proc_v4':
869
870 self[:] = []
871
872
873 - def clean(self, to_keep=['set','add','load'],
874 remove_bef_last=None,
875 to_remove=['open','display','launch', 'check','history'],
876 allow_for_removal=None,
877 keep_switch=False):
878 """Remove command in arguments from history.
879 All command before the last occurrence of 'remove_bef_last'
880 (including it) will be removed (but if another options tells the opposite).
881 'to_keep' is a set of line to always keep.
882 'to_remove' is a set of line to always remove (don't care about remove_bef_
883 status but keep_switch acts.).
884 if 'allow_for_removal' is define only the command in that list can be
885 remove of the history for older command that remove_bef_lb1. all parameter
886 present in to_remove are always remove even if they are not part of this
887 list.
888 keep_switch force to keep the statement remove_bef_??? which changes starts
889 the removal mode.
890 """
891
892
893 if __debug__ and allow_for_removal:
894 for arg in to_keep:
895 assert arg not in allow_for_removal
896
897
898 nline = -1
899 removal = False
900
901 while nline > -len(self):
902 switch = False
903
904
905 if not removal and remove_bef_last:
906 if self[nline].startswith(remove_bef_last):
907 removal = True
908 switch = True
909
910
911 if switch and keep_switch:
912 nline -= 1
913 continue
914
915
916 if any([self[nline].startswith(arg) for arg in to_remove]):
917 self.pop(nline)
918 continue
919
920
921 if removal:
922 if allow_for_removal:
923
924 if any([self[nline].startswith(arg)
925 for arg in allow_for_removal]):
926 self.pop(nline)
927 continue
928 elif not any([self[nline].startswith(arg) for arg in to_keep]):
929
930 self.pop(nline)
931 continue
932
933
934 nline -= 1
935
936 - def get(self, tag, default=None):
937 if isinstance(tag, int):
938 list.__getattr__(self, tag)
939 elif tag == 'info' or tag == "__setstate__":
940 return default
941 elif tag == "multiparticles":
942 out = []
943 for line in self:
944 if line.startswith('define'):
945 try:
946 name, content = line[7:].split('=',1)
947 except ValueError:
948 name, content = line[7:].split(None,1)
949 out.append((name, content))
950 return out
951 else:
952 return self.info[tag]
953
955 """write the proc_card to a given path"""
956
957 fsock = open(path, 'w')
958 fsock.write(self.history_header)
959 for line in self:
960 while len(line) > 70:
961 sub, line = line[:70]+"\\" , line[70:]
962 fsock.write(sub+"\n")
963 else:
964 fsock.write(line+"\n")
965
967
969 """ a class for storing/dealing with input file.
970 """
971
972 - def __init__(self, finput=None, **opt):
973 """initialize a new instance. input can be an instance of MadLoopParam,
974 a file, a path to a file, or simply Nothing"""
975
976 if isinstance(finput, self.__class__):
977 dict.__init__(self, finput)
978 for key in finput.__dict__:
979 setattr(self, key, copy.copy(getattr(finput, key)) )
980 for key,value in finput.items():
981 dict.__setitem__(self, key.lower(), value)
982 return
983 else:
984 dict.__init__(self)
985
986
987 self.user_set = set()
988 self.auto_set = set()
989 self.system_only = set()
990 self.lower_to_case = {}
991 self.list_parameter = {}
992 self.dict_parameter = {}
993 self.comments = {}
994
995 self.allowed_value = {}
996
997 self.default_setup()
998
999
1000
1001 if isinstance(finput, (file, str, StringIO.StringIO)):
1002 self.read(finput, **opt)
1003
1006
1008 return self.__class__(self)
1009
1011 """define the sum"""
1012 assert isinstance(other, dict)
1013 base = self.__class__(self)
1014
1015 base.update((key.lower(),value) for key, value in other.items())
1016
1017 return base
1018
1020 """define the sum"""
1021 new = copy.copy(other)
1022 new.update((key, value) for key, value in self.items())
1023 return new
1024
1027
1032
1033
1034
1035
1036
1037
1040
1043
1044 @staticmethod
1045 - def warn(text, level, raiseerror=False):
1046 """convenient proxy to raiseerror/print warning"""
1047
1048 if raiseerror is True:
1049 raise InvalidCardEdition(text)
1050 elif raiseerror:
1051 raise raiseerror(text)
1052
1053 if isinstance(level,str):
1054 log = getattr(logger, level.lower())
1055 elif isinstance(level, int):
1056 log = lambda t: logger.log(level, t)
1057 elif level:
1058 log = level
1059
1060 return log(text)
1061
1062 - def post_set(self, name, value, change_userdefine, raiseerror):
1063
1064 if value is None:
1065 value = self[name]
1066
1067 if hasattr(self, 'post_set_%s' % name):
1068 return getattr(self, 'post_set_%s' % name)(value, change_userdefine, raiseerror)
1069
1070 - def __setitem__(self, name, value, change_userdefine=False,raiseerror=False):
1071 """set the attribute and set correctly the type if the value is a string.
1072 change_userdefine on True if we have to add the parameter in user_set
1073 """
1074
1075 if not len(self):
1076
1077 self.__init__()
1078
1079 name = name.strip()
1080 lower_name = name.lower()
1081
1082
1083 if change_userdefine and lower_name in self.system_only:
1084 text='%s is a private entry which can not be modify by the user. Keep value at %s' % (name,self[name])
1085 self.warn(text, 'critical', raiseerror)
1086 return
1087
1088
1089 if lower_name in self:
1090 targettype = type(dict.__getitem__(self, lower_name))
1091 if targettype != str and isinstance(value, str) and value.lower() == 'auto':
1092 self.auto_set.add(lower_name)
1093 if lower_name in self.user_set:
1094 self.user_set.remove(lower_name)
1095
1096 self.post_set(lower_name, 'auto', change_userdefine, raiseerror)
1097 return
1098 elif lower_name in self.auto_set:
1099 self.auto_set.remove(lower_name)
1100
1101
1102 if lower_name in self.list_parameter:
1103 targettype = self.list_parameter[lower_name]
1104
1105
1106
1107 if isinstance(value, str):
1108
1109 value = value.strip()
1110 if value.startswith('[') and value.endswith(']'):
1111 value = value[1:-1]
1112
1113 data = re.split(r"((?<![\\])['\"])((?:.(?!(?<![\\])\1))*.?)\1", str(value))
1114 new_value = []
1115 i = 0
1116 while len(data) > i:
1117 current = [_f for _f in re.split(r'(?:(?<!\\)\s)|,', data[i]) if _f]
1118 i+=1
1119 if len(data) > i+1:
1120 if current:
1121 current[-1] += '{0}{1}{0}'.format(data[i], data[i+1])
1122 else:
1123 current = ['{0}{1}{0}'.format(data[i], data[i+1])]
1124 i+=2
1125 new_value += current
1126
1127 value = new_value
1128
1129 elif not hasattr(value, '__iter__'):
1130 value = [value]
1131 elif isinstance(value, dict):
1132 text = "not being able to handle dictionary in card entry"
1133 return self.warn(text, 'critical', raiseerror)
1134
1135
1136 values =[self.format_variable(v, targettype, name=name)
1137 for v in value]
1138
1139
1140 if lower_name in self.allowed_value and '*' not in self.allowed_value[lower_name]:
1141 new_values = []
1142 dropped = []
1143 for val in values:
1144 allowed = self.allowed_value[lower_name]
1145
1146 if val in allowed:
1147 new_values.append(val)
1148 continue
1149 elif isinstance(val, str):
1150 val = val.lower()
1151 allowed = allowed.lower()
1152 if value in allowed:
1153 i = allowed.index(value)
1154 new_values.append(self.allowed_value[i])
1155 continue
1156
1157 dropped.append(val)
1158
1159 if not new_values:
1160
1161 text= "value '%s' for entry '%s' is not valid. Preserving previous value: '%s'.\n" \
1162 % (value, name, self[lower_name])
1163 text += "allowed values are any list composed of the following entry: %s" % ', '.join([str(i) for i in self.allowed_value[lower_name]])
1164 return self.warn(text, 'warning', raiseerror)
1165 elif dropped:
1166 text = "some value for entry '%s' are not valid. Invalid item are: '%s'.\n" \
1167 % (value, name, dropped)
1168 text += "value will be set to %s" % new_values
1169 text += "allowed items in the list are: %s" % ', '.join([str(i) for i in self.allowed_value[lower_name]])
1170 self.warn(text, 'warning')
1171
1172 values = new_values
1173
1174
1175 dict.__setitem__(self, lower_name, values)
1176 if change_userdefine:
1177 self.user_set.add(lower_name)
1178
1179 return self.post_set(lower_name, None, change_userdefine, raiseerror)
1180 elif lower_name in self.dict_parameter:
1181 targettype = self.dict_parameter[lower_name]
1182 full_reset = True
1183
1184 if isinstance(value, str):
1185 value = value.strip()
1186
1187
1188
1189
1190
1191
1192
1193 if value.startswith('{') and value.endswith('}'):
1194 new_value = {}
1195 for pair in value[1:-1].split(','):
1196 if not pair.strip():
1197 break
1198 x, y = pair.split(':')
1199 x, y = x.strip(), y.strip()
1200 if x.startswith(('"',"'")) and x.endswith(x[0]):
1201 x = x[1:-1]
1202 new_value[x] = y
1203 value = new_value
1204 elif ',' in value:
1205 x,y = value.split(',')
1206 value = {x.strip():y.strip()}
1207 full_reset = False
1208
1209 elif ':' in value:
1210 x,y = value.split(':')
1211 value = {x.strip():y.strip()}
1212 full_reset = False
1213 else:
1214 x,y = value.split()
1215 value = {x:y}
1216 full_reset = False
1217
1218 if isinstance(value, dict):
1219 for key in value:
1220 value[key] = self.format_variable(value[key], targettype, name=name)
1221 if full_reset:
1222 dict.__setitem__(self, lower_name, value)
1223 else:
1224 dict.__getitem__(self, lower_name).update(value)
1225 else:
1226 raise Exception('%s should be of dict type'% lower_name)
1227 if change_userdefine:
1228 self.user_set.add(lower_name)
1229 return self.post_set(lower_name, None, change_userdefine, raiseerror)
1230 elif name in self:
1231 targettype = type(self[name])
1232 else:
1233 logger.debug('Trying to add argument %s in %s. ' % (name, self.__class__.__name__) +\
1234 'This argument is not defined by default. Please consider adding it.')
1235 suggestions = [k for k in self.keys() if k.startswith(name[0].lower())]
1236 if len(suggestions)>0:
1237 logger.debug("Did you mean one of the following: %s"%suggestions)
1238 self.add_param(lower_name, self.format_variable(UnknownType(value),
1239 UnknownType, name))
1240 self.lower_to_case[lower_name] = name
1241 if change_userdefine:
1242 self.user_set.add(lower_name)
1243 return self.post_set(lower_name, None, change_userdefine, raiseerror)
1244
1245 value = self.format_variable(value, targettype, name=name)
1246
1247 if lower_name in self.allowed_value and '*' not in self.allowed_value[lower_name]:
1248 valid = False
1249 allowed = self.allowed_value[lower_name]
1250
1251
1252 if value in allowed:
1253 valid=True
1254 elif isinstance(value, str):
1255 value = value.lower().strip()
1256 allowed = [str(v).lower() for v in allowed]
1257 if value in allowed:
1258 i = allowed.index(value)
1259 value = self.allowed_value[lower_name][i]
1260 valid=True
1261
1262 if not valid:
1263
1264 text = "value '%s' for entry '%s' is not valid. Preserving previous value: '%s'.\n" \
1265 % (value, name, self[lower_name])
1266 text += "allowed values are %s\n" % ', '.join([str(i) for i in self.allowed_value[lower_name]])
1267 if lower_name in self.comments:
1268 text += 'type "help %s" for more information' % name
1269 return self.warn(text, 'warning', raiseerror)
1270
1271 dict.__setitem__(self, lower_name, value)
1272 if change_userdefine:
1273 self.user_set.add(lower_name)
1274 self.post_set(lower_name, None, change_userdefine, raiseerror)
1275
1276
1277 - def add_param(self, name, value, system=False, comment=False, typelist=None,
1278 allowed=[]):
1279 """add a default parameter to the class"""
1280
1281 lower_name = name.lower()
1282 if __debug__:
1283 if lower_name in self:
1284 raise Exception("Duplicate case for %s in %s" % (name,self.__class__))
1285
1286 dict.__setitem__(self, lower_name, value)
1287 self.lower_to_case[lower_name] = name
1288 if isinstance(value, list):
1289 if len(value):
1290 targettype = type(value[0])
1291 else:
1292 targettype=typelist
1293 assert typelist
1294 if any([targettype != type(v) for v in value]):
1295 raise Exception("All entry should have the same type")
1296 self.list_parameter[lower_name] = targettype
1297 elif isinstance(value, dict):
1298 allvalues = list(value.values())
1299 if any([type(allvalues[0]) != type(v) for v in allvalues]):
1300 raise Exception("All entry should have the same type")
1301 self.dict_parameter[lower_name] = type(allvalues[0])
1302 if '__type__' in value:
1303 del value['__type__']
1304 dict.__setitem__(self, lower_name, value)
1305
1306 if allowed and allowed != ['*']:
1307 self.allowed_value[lower_name] = allowed
1308 assert value in allowed or '*' in allowed
1309
1310
1311
1312
1313 if system:
1314 self.system_only.add(lower_name)
1315 if comment:
1316 self.comments[lower_name] = comment
1317
1319 """return a minimal help for the parameter"""
1320
1321 out = "## Information on parameter %s from class %s\n" % (name, self.__class__.__name__)
1322 if name.lower() in self:
1323 out += "## current value: %s (parameter should be of type %s)\n" % (self[name], type(self[name]))
1324 if name.lower() in self.comments:
1325 out += '## %s\n' % self.comments[name.lower()].replace('\n', '\n## ')
1326 else:
1327 out += "## Unknown for this class\n"
1328 if name.lower() in self.user_set:
1329 out += "## This value is considered as been set by the user\n"
1330 else:
1331 out += "## This value is considered as been set by the system\n"
1332 if name.lower() in self.allowed_value:
1333 if '*' not in self.allowed_value[name.lower()]:
1334 out += "Allowed value are: %s\n" % ','.join([str(p) for p in self.allowed_value[name.lower()]])
1335 else:
1336 out += "Suggested value are : %s\n " % ','.join([str(p) for p in self.allowed_value[name.lower()] if p!='*'])
1337
1338 logger.info(out)
1339 return out
1340
1341 @staticmethod
1448
1449
1450
1452
1453 lower_name = name.lower()
1454 if __debug__:
1455 if lower_name not in self:
1456 if lower_name in [key.lower() for key in self] :
1457 raise Exception("Some key are not lower case %s. Invalid use of the class!"\
1458 % [key for key in self if key.lower() != key])
1459
1460 if lower_name in self.auto_set:
1461 return 'auto'
1462
1463 return dict.__getitem__(self, name.lower())
1464
1465
1466 - def set(self, name, value, changeifuserset=True, user=False, raiseerror=False):
1467 """convenient way to change attribute.
1468 changeifuserset=False means that the value is NOT change is the value is not on default.
1469 user=True, means that the value will be marked as modified by the user
1470 (potentially preventing future change to the value)
1471 """
1472
1473
1474 if not changeifuserset:
1475 if name.lower() in self.user_set:
1476
1477 return
1478
1479 self.__setitem__(name, value, change_userdefine=user, raiseerror=raiseerror)
1480
1484 """A class to handle information which are passed from MadGraph to the madevent
1485 interface."""
1486
1488 """initialize the directory to the default value"""
1489
1490 self.add_param('loop_induced', False)
1491 self.add_param('has_isr', False)
1492 self.add_param('has_fsr', False)
1493 self.add_param('nb_channel', 0)
1494 self.add_param('nexternal', 0)
1495 self.add_param('ninitial', 0)
1496 self.add_param('grouped_matrix', True)
1497 self.add_param('has_loops', False)
1498 self.add_param('bias_module','None')
1499 self.add_param('max_n_matched_jets', 0)
1500 self.add_param('colored_pdgs', [1,2,3,4,5])
1501 self.add_param('complex_mass_scheme', False)
1502 self.add_param('pdg_initial1', [0])
1503 self.add_param('pdg_initial2', [0])
1504 self.add_param('limitations', [], typelist=str)
1505
1506 - def read(self, finput):
1507 """Read the input file, this can be a path to a file,
1508 a file object, a str with the content of the file."""
1509
1510 if isinstance(finput, str):
1511 if "\n" in finput:
1512 finput = finput.split('\n')
1513 elif os.path.isfile(finput):
1514 finput = open(finput)
1515 else:
1516 raise Exception("No such file %s" % finput)
1517
1518 for line in finput:
1519 if '#' in line:
1520 line = line.split('#',1)[0]
1521 if not line:
1522 continue
1523
1524 if '=' in line:
1525 key, value = line.split('=',1)
1526 self[key.strip()] = value
1527
1528 - def write(self, outputpath):
1529 """write the file"""
1530
1531 template ="# Information about the process #\n"
1532 template +="#########################################\n"
1533
1534 fsock = open(outputpath, 'w')
1535 fsock.write(template)
1536
1537 for key, value in self.items():
1538 fsock.write(" %s = %s \n" % (key, value))
1539
1540 fsock.close()
1541
1546 """an object for the GridpackCard"""
1547
1549 """default value for the GridpackCard"""
1550
1551 self.add_param("GridRun", True)
1552 self.add_param("gevents", 2500)
1553 self.add_param("gseed", 1)
1554 self.add_param("ngran", -1)
1555
1556 - def read(self, finput):
1557 """Read the input file, this can be a path to a file,
1558 a file object, a str with the content of the file."""
1559
1560 if isinstance(finput, str):
1561 if "\n" in finput:
1562 finput = finput.split('\n')
1563 elif os.path.isfile(finput):
1564 finput = open(finput)
1565 else:
1566 raise Exception("No such file %s" % finput)
1567
1568 for line in finput:
1569 line = line.split('#')[0]
1570 line = line.split('!')[0]
1571 line = line.split('=',1)
1572 if len(line) != 2:
1573 continue
1574 self[line[1].strip()] = line[0].replace('\'','').strip()
1575
1576 - def write(self, output_file, template=None):
1577 """Write the run_card in output_file according to template
1578 (a path to a valid run_card)"""
1579
1580 if not template:
1581 if not MADEVENT:
1582 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
1583 'grid_card_default.dat')
1584 else:
1585 template = pjoin(MEDIR, 'Cards', 'grid_card_default.dat')
1586
1587
1588 text = ""
1589 for line in open(template,'r'):
1590 nline = line.split('#')[0]
1591 nline = nline.split('!')[0]
1592 comment = line[len(nline):]
1593 nline = nline.split('=')
1594 if len(nline) != 2:
1595 text += line
1596 elif nline[1].strip() in self:
1597 text += ' %s\t= %s %s' % (self[nline[1].strip()],nline[1], comment)
1598 else:
1599 logger.info('Adding missing parameter %s to current run_card (with default value)' % nline[1].strip())
1600 text += line
1601
1602 if isinstance(output_file, str):
1603 fsock = open(output_file,'w')
1604 else:
1605 fsock = output_file
1606
1607 fsock.write(text)
1608 fsock.close()
1609
1611 """ Implements the Pythia8 card."""
1612
1614 """ Placeholder function to allow overwriting in the PY8SubRun daughter.
1615 The initialization of the self.subruns attribute should of course not
1616 be performed in PY8SubRun."""
1617 if type == 'parameters':
1618 if "LHEFInputs:nSubruns" not in self:
1619 self.add_param("LHEFInputs:nSubruns", 1,
1620 hidden='ALWAYS_WRITTEN',
1621 comment="""
1622 ====================
1623 Subrun definitions
1624 ====================
1625 """)
1626 if type == 'attributes':
1627 if not(hasattr(self,'subruns')):
1628 first_subrun = PY8SubRun(subrun_id=0)
1629 self.subruns = dict([(first_subrun['Main:subrun'],first_subrun)])
1630
1632 """ Sets up the list of available PY8 parameters."""
1633
1634
1635
1636 self.add_param("Main:numberOfEvents", -1)
1637
1638
1639 self.add_param("JetMatching:qCut", -1.0, always_write_to_card=False)
1640 self.add_param("JetMatching:doShowerKt",False,always_write_to_card=False)
1641
1642 self.add_param("JetMatching:nJetMax", -1, always_write_to_card=False)
1643
1644 self.add_param("Merging:TMS", -1.0, always_write_to_card=False)
1645 self.add_param("Merging:Process", '<set_by_user>', always_write_to_card=False)
1646
1647 self.add_param("Merging:nJetMax", -1, always_write_to_card=False)
1648
1649
1650 self.add_param("SysCalc:fullCutVariation", False)
1651
1652
1653
1654 self.add_param("HEPMCoutput:file", 'auto')
1655
1656
1657
1658 self.add_param("Beams:frameType", 4,
1659 hidden=True,
1660 comment='Tell Pythia8 that an LHEF input is used.')
1661 self.add_param("HEPMCoutput:scaling", 1.0e9,
1662 hidden=True,
1663 comment='1.0 corresponds to HEPMC weight given in [mb]. We choose here the [pb] normalization.')
1664 self.add_param("Check:epTolErr", 1e-2,
1665 hidden=True,
1666 comment='Be more forgiving with momentum mismatches.')
1667
1668
1669 self.add_param("JetMatching:etaJetMax", 1000.0, hidden=True, always_write_to_card=True)
1670
1671
1672
1673 self.add_param("PDF:pSet", 'LHAPDF5:CT10.LHgrid', hidden=True, always_write_to_card=False,
1674 comment='Reminder: Parameter below is shower tune dependent.')
1675 self.add_param("SpaceShower:alphaSvalue", 0.118, hidden=True, always_write_to_card=False,
1676 comment='Reminder: Parameter below is shower tune dependent.')
1677 self.add_param("TimeShower:alphaSvalue", 0.118, hidden=True, always_write_to_card=False,
1678 comment='Reminder: Parameter below is shower tune dependent.')
1679 self.add_param("hadronlevel:all", True, hidden=True, always_write_to_card=False,
1680 comment='This allows to turn on/off hadronization alltogether.')
1681 self.add_param("partonlevel:mpi", True, hidden=True, always_write_to_card=False,
1682 comment='This allows to turn on/off MPI alltogether.')
1683 self.add_param("Beams:setProductionScalesFromLHEF", False, hidden=True,
1684 always_write_to_card=False,
1685 comment='This parameter is automatically set to True by MG5aMC when doing MLM merging with PY8.')
1686
1687
1688 self.add_param("JetMatching:merge", False, hidden=True, always_write_to_card=False,
1689 comment='Specifiy if we are merging sample of different multiplicity.')
1690 self.add_param("SysCalc:qCutList", [10.0,20.0], hidden=True, always_write_to_card=False)
1691 self['SysCalc:qCutList'] = 'auto'
1692 self.add_param("SysCalc:qWeed",-1.0,hidden=True, always_write_to_card=False,
1693 comment='Value of the merging scale below which one does not even write the HepMC event.')
1694 self.add_param("JetMatching:doVeto", False, hidden=True, always_write_to_card=False,
1695 comment='Do veto externally (e.g. in SysCalc).')
1696 self.add_param("JetMatching:scheme", 1, hidden=True, always_write_to_card=False)
1697 self.add_param("JetMatching:setMad", False, hidden=True, always_write_to_card=False,
1698 comment='Specify one must read inputs from the MadGraph banner.')
1699 self.add_param("JetMatching:coneRadius", 1.0, hidden=True, always_write_to_card=False)
1700 self.add_param("JetMatching:nQmatch",4,hidden=True, always_write_to_card=False)
1701
1702 self.add_param("TimeShower:pTmaxMatch", 2, hidden=True, always_write_to_card=False)
1703 self.add_param("SpaceShower:pTmaxMatch", 1, hidden=True, always_write_to_card=False)
1704 self.add_param("SysCalc:tmsList", [10.0,20.0], hidden=True, always_write_to_card=False)
1705 self['SysCalc:tmsList'] = 'auto'
1706 self.add_param("Merging:muFac", 91.188, hidden=True, always_write_to_card=False,
1707 comment='Set factorisation scales of the 2->2 process.')
1708 self.add_param("Merging:applyVeto", False, hidden=True, always_write_to_card=False,
1709 comment='Do veto externally (e.g. in SysCalc).')
1710 self.add_param("Merging:includeWeightInXsection", True, hidden=True, always_write_to_card=False,
1711 comment='If turned off, then the option belows forces PY8 to keep the original weight.')
1712 self.add_param("Merging:muRen", 91.188, hidden=True, always_write_to_card=False,
1713 comment='Set renormalization scales of the 2->2 process.')
1714 self.add_param("Merging:muFacInME", 91.188, hidden=True, always_write_to_card=False,
1715 comment='Set factorisation scales of the 2->2 Matrix Element.')
1716 self.add_param("Merging:muRenInME", 91.188, hidden=True, always_write_to_card=False,
1717 comment='Set renormalization scales of the 2->2 Matrix Element.')
1718 self.add_param("SpaceShower:rapidityOrder", False, hidden=True, always_write_to_card=False)
1719 self.add_param("Merging:nQuarksMerge",4,hidden=True, always_write_to_card=False)
1720
1721 self.add_param("Merging:mayRemoveDecayProducts", False, hidden=True, always_write_to_card=False)
1722 self.add_param("Merging:doKTMerging", False, hidden=True, always_write_to_card=False)
1723 self.add_param("Merging:Dparameter", 0.4, hidden=True, always_write_to_card=False)
1724 self.add_param("Merging:doPTLundMerging", False, hidden=True, always_write_to_card=False)
1725
1726
1727 self.add_param("BeamRemnants:primordialKT", True, hidden=True, always_write_to_card=False, comment="see http://home.thep.lu.se/~torbjorn/pythia82html/BeamRemnants.html")
1728 self.add_param("PartonLevel:Remnants", True, hidden=True, always_write_to_card=False, comment="Master switch for addition of beam remnants. Cannot be used to generate complete events")
1729 self.add_param("Check:event", True, hidden=True, always_write_to_card=False, comment="check physical sanity of the events")
1730 self.add_param("TimeShower:QEDshowerByQ", True, hidden=True, always_write_to_card=False, comment="Allow quarks to radiate photons for FSR, i.e. branchings q -> q gamma")
1731 self.add_param("TimeShower:QEDshowerByL", True, hidden=True, always_write_to_card=False, comment="Allow leptons to radiate photons for FSR, i.e. branchings l -> l gamma")
1732 self.add_param("SpaceShower:QEDshowerByQ", True, hidden=True, always_write_to_card=False, comment="Allow quarks to radiate photons for ISR, i.e. branchings q -> q gamma")
1733 self.add_param("SpaceShower:QEDshowerByL", True, hidden=True, always_write_to_card=False, comment="Allow leptons to radiate photonsfor ISR, i.e. branchings l -> l gamma")
1734 self.add_param("PartonLevel:FSRinResonances", True, hidden=True, always_write_to_card=False, comment="Do not allow shower to run from decay product of unstable particle")
1735 self.add_param("ProcessLevel:resonanceDecays", True, hidden=True, always_write_to_card=False, comment="Do not allow unstable particle to decay.")
1736
1737
1738
1739 self.add_default_subruns('parameters')
1740
1742
1743
1744
1745 self.hidden_param = []
1746 self.hidden_params_to_always_write = set()
1747 self.visible_params_to_always_write = set()
1748
1749 self.params_to_never_write = set()
1750
1751
1752
1753 self.system_set = set()
1754
1755
1756
1757 self.add_default_subruns('attributes')
1758
1759
1760 super(PY8Card, self).__init__(*args, **opts)
1761
1762 - def add_param(self, name, value, hidden=False, always_write_to_card=True,
1763 comment=None):
1764 """ add a parameter to the card. value is the default value and
1765 defines the type (int/float/bool/str) of the input.
1766 The option 'hidden' decides whether the parameter should be visible to the user.
1767 The option 'always_write_to_card' decides whether it should
1768 always be printed or only when it is system_set or user_set.
1769 The option 'comment' can be used to specify a comment to write above
1770 hidden parameters.
1771 """
1772 super(PY8Card, self).add_param(name, value, comment=comment)
1773 name = name.lower()
1774 if hidden:
1775 self.hidden_param.append(name)
1776 if always_write_to_card:
1777 self.hidden_params_to_always_write.add(name)
1778 else:
1779 if always_write_to_card:
1780 self.visible_params_to_always_write.add(name)
1781 if not comment is None:
1782 if not isinstance(comment, str):
1783 raise MadGraph5Error("Option 'comment' must be a string, not"+\
1784 " '%s'."%str(comment))
1785
1787 """Add a subrun to this PY8 Card."""
1788 assert(isinstance(py8_subrun,PY8SubRun))
1789 if py8_subrun['Main:subrun']==-1:
1790 raise MadGraph5Error("Make sure to correctly set the subrun ID"+\
1791 " 'Main:subrun' *before* adding it to the PY8 Card.")
1792 if py8_subrun['Main:subrun'] in self.subruns:
1793 raise MadGraph5Error("A subrun with ID '%s'"%py8_subrun['Main:subrun']+\
1794 " is already present in this PY8 card. Remove it first, or "+\
1795 " access it directly.")
1796 self.subruns[py8_subrun['Main:subrun']] = py8_subrun
1797 if not 'LHEFInputs:nSubruns' in self.user_set:
1798 self['LHEFInputs:nSubruns'] = max(self.subruns.keys())
1799
1800 - def userSet(self, name, value, **opts):
1801 """Set an attribute of this card, following a user_request"""
1802 self.__setitem__(name, value, change_userdefine=True, **opts)
1803 if name.lower() in self.system_set:
1804 self.system_set.remove(name.lower())
1805
1807 """ Forbid the writeout of a specific parameter of this card when the
1808 "write" function will be invoked."""
1809 self.params_to_never_write.add(name.lower())
1810
1812 """Set an attribute of this card, independently of a specific user
1813 request and only if not already user_set."""
1814 try:
1815 force = opts.pop('force')
1816 except KeyError:
1817 force = False
1818 if force or name.lower() not in self.user_set:
1819 self.__setitem__(name, value, change_userdefine=False, **opts)
1820 self.system_set.add(name.lower())
1821
1823 """ Sets a card attribute, but only if it is absent or not already
1824 user_set."""
1825 try:
1826 force = opts.pop('force')
1827 except KeyError:
1828 force = False
1829 if name.lower() not in self or (force or name.lower() not in self.user_set):
1830 self.__setitem__(name, value, change_userdefine=False, **opts)
1831 self.system_set.add(name.lower())
1832
1835
1836 @staticmethod
1887
1888
1889 - def write(self, output_file, template, read_subrun=False,
1890 print_only_visible=False, direct_pythia_input=False, add_missing=True):
1891 """ Write the card to output_file using a specific template.
1892 > 'print_only_visible' specifies whether or not the hidden parameters
1893 should be written out if they are in the hidden_params_to_always_write
1894 list and system_set.
1895 > If 'direct_pythia_input' is true, then visible parameters which are not
1896 in the self.visible_params_to_always_write list and are not user_set
1897 or system_set are commented.
1898 > If 'add_missing' is False then parameters that should be written_out but are absent
1899 from the template will not be written out."""
1900
1901
1902 visible_param = [p for p in self if p.lower() not in self.hidden_param
1903 or p.lower() in self.user_set]
1904
1905 visible_param = [p for p in visible_param if p.lower() not in self.params_to_never_write]
1906
1907
1908 if print_only_visible:
1909 hidden_output_param = []
1910 else:
1911 hidden_output_param = [p for p in self if p.lower() in self.hidden_param and
1912 not p.lower() in self.user_set and
1913 (p.lower() in self.hidden_params_to_always_write or
1914 p.lower() in self.system_set)]
1915
1916 hidden_output_param = [p for p in hidden_output_param if p not in self.params_to_never_write]
1917
1918 if print_only_visible:
1919 subruns = []
1920 else:
1921 if not read_subrun:
1922 subruns = sorted(self.subruns.keys())
1923
1924
1925
1926 subruns_to_write = {}
1927
1928
1929
1930 def group_params(params):
1931 if len(params)==0:
1932 return []
1933 groups = {}
1934 for p in params:
1935 try:
1936 groups[':'.join(p.split(':')[:-1])].append(p)
1937 except KeyError:
1938 groups[':'.join(p.split(':')[:-1])] = [p,]
1939 res = sum(list(groups.values()),[])
1940
1941 if 'Main:subrun' in res:
1942 res.insert(0,res.pop(res.index('Main:subrun')))
1943
1944 if 'LHEFInputs:nSubruns' in res:
1945 res.append(res.pop(res.index('LHEFInputs:nSubruns')))
1946 return res
1947
1948 visible_param = group_params(visible_param)
1949 hidden_output_param = group_params(hidden_output_param)
1950
1951
1952
1953 output = StringIO.StringIO()
1954
1955
1956 if isinstance(template, str):
1957 if os.path.isfile(template):
1958 tmpl = open(template, 'r')
1959 elif '\n' in template:
1960 tmpl = StringIO.StringIO(template)
1961 else:
1962 raise Exception("File input '%s' not found." % file_input)
1963 elif template is None:
1964
1965 tmpl = StringIO.StringIO()
1966 elif isinstance(template, (StringIO.StringIO, file)):
1967 tmpl = template
1968 else:
1969 raise MadGraph5Error("Incorrect type for argument 'template': %s"%
1970 template.__class__.__name__)
1971
1972
1973 last_pos = tmpl.tell()
1974 line = tmpl.readline()
1975 started_subrun_reading = False
1976 while line!='':
1977
1978 if line.strip().startswith('!') or \
1979 line.strip().startswith('\n') or\
1980 line.strip() == '':
1981 output.write(line)
1982
1983 last_pos = tmpl.tell()
1984 line = tmpl.readline()
1985 continue
1986
1987 try:
1988 param_entry, value_entry = line.split('=')
1989 param = param_entry.strip()
1990 value = value_entry.strip()
1991 except ValueError:
1992 line = line.replace('\n','')
1993 raise MadGraph5Error("Could not read line '%s' of Pythia8 card."%\
1994 line)
1995
1996 if param=='Main:subrun':
1997 if read_subrun:
1998 if not started_subrun_reading:
1999
2000 started_subrun_reading = True
2001 else:
2002
2003 tmpl.seek(last_pos)
2004 break
2005 else:
2006
2007 tmpl.seek(last_pos)
2008 subruns_to_write[int(value)] = StringIO.StringIO()
2009 if int(value) in subruns:
2010 self.subruns[int(value)].write(subruns_to_write[int(value)],
2011 tmpl,read_subrun=True)
2012
2013 subruns.pop(subruns.index(int(value)))
2014 else:
2015
2016 DummySubrun=PY8SubRun()
2017
2018 DummySubrun.clear()
2019 DummySubrun.write(subruns_to_write[int(value)],
2020 tmpl, read_subrun=True,
2021 print_only_visible=print_only_visible,
2022 direct_pythia_input=direct_pythia_input)
2023
2024 logger.info('Adding new unknown subrun with ID %d.'%
2025 int(value))
2026
2027 last_pos = tmpl.tell()
2028 line = tmpl.readline()
2029 continue
2030
2031
2032 if param in visible_param:
2033 new_value = PY8Card.pythia8_formatting(self[param])
2034 visible_param.pop(visible_param.index(param))
2035 elif param in hidden_output_param:
2036 new_value = PY8Card.pythia8_formatting(self[param])
2037 hidden_output_param.pop(hidden_output_param.index(param))
2038 else:
2039
2040 if param.lower() not in self.params_to_never_write:
2041 output.write(line)
2042 else:
2043 output.write('! The following parameter was forced to be commented out by MG5aMC.\n')
2044 output.write('! %s'%line)
2045
2046 last_pos = tmpl.tell()
2047 line = tmpl.readline()
2048 continue
2049
2050
2051
2052
2053
2054 if ((not direct_pythia_input) or
2055 (param.lower() in self.visible_params_to_always_write) or
2056 (param.lower() in self.user_set) or
2057 (param.lower() in self.system_set)):
2058 template = '%s=%s'
2059 else:
2060
2061
2062
2063 template = '!%s=%s'
2064
2065 output.write(template%(param_entry,
2066 value_entry.replace(value,new_value)))
2067
2068
2069 last_pos = tmpl.tell()
2070 line = tmpl.readline()
2071
2072
2073 if not add_missing:
2074 visible_param = []
2075 hidden_output_param = []
2076
2077
2078 if len(visible_param)>0 and not template is None:
2079 output.write(
2080 """!
2081 ! Additional general parameters%s.
2082 !
2083 """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else ''))
2084 for param in visible_param:
2085 value = PY8Card.pythia8_formatting(self[param])
2086 output.write('%s=%s\n'%(param,value))
2087 if template is None:
2088 if param=='Main:subrun':
2089 output.write(
2090 """!
2091 ! Definition of subrun %d
2092 !
2093 """%self['Main:subrun'])
2094 elif param.lower() not in self.hidden_param:
2095 logger.debug('Adding parameter %s (missing in the template) to current '+\
2096 'pythia8 card (with value %s)',param, value)
2097
2098 if len(hidden_output_param)>0 and not template is None:
2099 output.write(
2100 """!
2101 ! Additional technical parameters%s set by MG5_aMC.
2102 !
2103 """%(' for subrun %d'%self['Main:subrun'] if 'Main:subrun' in self else ''))
2104 for param in hidden_output_param:
2105 if param.lower() in self.comments:
2106 comment = '\n'.join('! %s'%c for c in
2107 self.comments[param.lower()].split('\n'))
2108 output.write(comment+'\n')
2109 output.write('%s=%s\n'%(param,PY8Card.pythia8_formatting(self[param])))
2110
2111
2112
2113 if read_subrun:
2114 output_file.write(output.getvalue())
2115 return
2116
2117
2118 for subrunID in subruns:
2119 new_subrun = StringIO.StringIO()
2120 self.subruns[subrunID].write(new_subrun,None,read_subrun=True)
2121 subruns_to_write[subrunID] = new_subrun
2122
2123
2124 for subrunID in sorted(subruns_to_write):
2125 output.write(subruns_to_write[subrunID].getvalue())
2126
2127
2128
2129 if 'LHEFInputs:nSubruns'.lower() not in self.user_set and \
2130 len(subruns_to_write)>0 and 'LHEFInputs:nSubruns' in self\
2131 and self['LHEFInputs:nSubruns']<max(subruns_to_write.keys()):
2132 logger.info("Updating PY8 parameter 'LHEFInputs:nSubruns' to "+
2133 "%d so as to cover all defined subruns."%max(subruns_to_write.keys()))
2134 self['LHEFInputs:nSubruns'] = max(subruns_to_write.keys())
2135 output = StringIO.StringIO()
2136 self.write(output,template,print_only_visible=print_only_visible)
2137
2138
2139 if isinstance(output_file, str):
2140 out = open(output_file,'w')
2141 out.write(output.getvalue())
2142 out.close()
2143 else:
2144 output_file.write(output.getvalue())
2145
2146 - def read(self, file_input, read_subrun=False, setter='default'):
2147 """Read the input file, this can be a path to a file,
2148 a file object, a str with the content of the file.
2149 The setter option choses the authority that sets potential
2150 modified/new parameters. It can be either:
2151 'default' or 'user' or 'system'"""
2152 if isinstance(file_input, str):
2153 if "\n" in file_input:
2154 finput = StringIO.StringIO(file_input)
2155 elif os.path.isfile(file_input):
2156 finput = open(file_input)
2157 else:
2158 raise Exception("File input '%s' not found." % file_input)
2159 elif isinstance(file_input, (StringIO.StringIO, file)):
2160 finput = file_input
2161 else:
2162 raise MadGraph5Error("Incorrect type for argument 'file_input': %s"%
2163 file_input.__class__.__name__)
2164
2165
2166 last_pos = finput.tell()
2167 line = finput.readline()
2168 started_subrun_reading = False
2169 while line!='':
2170
2171 if line.strip().startswith('!') or line.strip()=='':
2172
2173 last_pos = finput.tell()
2174 line = finput.readline()
2175 continue
2176
2177 try:
2178 param, value = line.split('=',1)
2179 param = param.strip()
2180 value = value.strip()
2181 except ValueError:
2182 line = line.replace('\n','')
2183 raise MadGraph5Error("Could not read line '%s' of Pythia8 card."%\
2184 line)
2185 if '!' in value:
2186 value,_ = value.split('!',1)
2187
2188
2189 if param=='Main:subrun':
2190 if read_subrun:
2191 if not started_subrun_reading:
2192
2193 started_subrun_reading = True
2194 else:
2195
2196 finput.seek(last_pos)
2197 return
2198 else:
2199
2200 finput.seek(last_pos)
2201 if int(value) in self.subruns:
2202 self.subruns[int(value)].read(finput,read_subrun=True,
2203 setter=setter)
2204 else:
2205
2206 NewSubrun=PY8SubRun()
2207 NewSubrun.read(finput,read_subrun=True, setter=setter)
2208 self.add_subrun(NewSubrun)
2209
2210
2211 last_pos = finput.tell()
2212 line = finput.readline()
2213 continue
2214
2215
2216
2217
2218
2219 if setter == 'user':
2220 self.userSet(param,value)
2221 elif setter == 'system':
2222 self.systemSet(param,value)
2223 else:
2224 self.defaultSet(param,value)
2225
2226
2227 last_pos = finput.tell()
2228 line = finput.readline()
2229
2231 """ Class to characterize a specific PY8 card subrun section. """
2232
2234 """ Overloading of the homonym function called in the __init__ of PY8Card.
2235 The initialization of the self.subruns attribute should of course not
2236 be performed in PY8SubRun."""
2237 pass
2238
2240 """ Initialize a subrun """
2241
2242
2243 subrunID = -1
2244 if 'subrun_id' in opts:
2245 subrunID = opts.pop('subrun_id')
2246
2247 super(PY8SubRun, self).__init__(*args, **opts)
2248 self['Main:subrun']=subrunID
2249
2251 """Sets up the list of available PY8SubRun parameters."""
2252
2253
2254 super(PY8SubRun, self).default_setup()
2255
2256 self.hidden_param = [k.lower() for k in self.keys()]
2257 self.hidden_params_to_always_write = set()
2258 self.visible_params_to_always_write = set()
2259
2260
2261 self.add_param("Main:subrun", -1)
2262 self.add_param("Beams:LHEF", "events.lhe.gz")
2263
2264
2265
2266 runblock = collections.namedtuple('block', ('name', 'fields', 'template_on', 'template_off'))
2268
2269 filename = 'run_card'
2270 blocks = []
2271
2272 - def __new__(cls, finput=None, **opt):
2273 if cls is RunCard:
2274 if not finput:
2275 target_class = RunCardLO
2276 elif isinstance(finput, cls):
2277 target_class = finput.__class__
2278 elif isinstance(finput, str):
2279 if '\n' not in finput:
2280 finput = open(finput).read()
2281 if 'req_acc_FO' in finput:
2282 target_class = RunCardNLO
2283 else:
2284 target_class = RunCardLO
2285 else:
2286 return None
2287 return super(RunCard, cls).__new__(target_class, finput, **opt)
2288 else:
2289 return super(RunCard, cls).__new__(cls, finput, **opt)
2290
2292
2293
2294
2295
2296 self.hidden_param = []
2297
2298 self.includepath = collections.defaultdict(list)
2299
2300 self.fortran_name = {}
2301
2302 self.legacy_parameter = {}
2303
2304
2305
2306
2307
2308 self.cuts_parameter = {}
2309
2310 self.system_default = {}
2311
2312 self.display_block = []
2313 self.cut_class = {}
2314 self.warned=False
2315
2316
2317 super(RunCard, self).__init__(*args, **opts)
2318
2319 - def add_param(self, name, value, fortran_name=None, include=True,
2320 hidden=False, legacy=False, cut=False, system=False, sys_default=None,
2321 **opts):
2322 """ add a parameter to the card. value is the default value and
2323 defines the type (int/float/bool/str) of the input.
2324 fortran_name defines what is the associate name in the f77 code
2325 include defines if we have to put the value in the include file
2326 hidden defines if the parameter is expected to be define by the user.
2327 legacy:Parameter which is not used anymore (raise a warning if not default)
2328 cut: defines the list of cut parameter to allow to set them all to off.
2329 sys_default: default used if the parameter is not in the card
2330
2331 options of **opts:
2332 - allowed: list of valid options. '*' means anything else should be allowed.
2333 empty list means anything possible as well.
2334 - comment: add comment for writing/help
2335 - typelist: type of the list if default is empty
2336 """
2337
2338 super(RunCard, self).add_param(name, value, system=system,**opts)
2339 name = name.lower()
2340 if fortran_name:
2341 self.fortran_name[name] = fortran_name
2342 if legacy:
2343 self.legacy_parameter[name] = value
2344 include = False
2345 self.includepath[include].append(name)
2346 if hidden or system:
2347 self.hidden_param.append(name)
2348 if cut:
2349 self.cuts_parameter[name] = cut
2350 if sys_default is not None:
2351 self.system_default[name] = sys_default
2352
2353
2354
2355 - def read(self, finput, consistency=True):
2356 """Read the input file, this can be a path to a file,
2357 a file object, a str with the content of the file."""
2358
2359 if isinstance(finput, str):
2360 if "\n" in finput:
2361 finput = finput.split('\n')
2362 elif os.path.isfile(finput):
2363 finput = open(finput)
2364 else:
2365 raise Exception("No such file %s" % finput)
2366
2367 for line in finput:
2368 line = line.split('#')[0]
2369 line = line.split('!')[0]
2370 line = line.rsplit('=',1)
2371 if len(line) != 2:
2372 continue
2373 value, name = line
2374 name = name.lower().strip()
2375 if name not in self and ('min' in name or 'max' in name):
2376
2377 self.add_param(name, float(value), hidden=True, cut=True)
2378 else:
2379 self.set( name, value, user=True)
2380
2381 if consistency:
2382 try:
2383 self.check_validity()
2384 except InvalidRunCard as error:
2385 if consistency == 'warning':
2386 logger.warning(str(error))
2387 else:
2388 raise
2389
2391 template_options = tmp
2392 default = template_options['default']
2393 if line.startswith('#IF('):
2394 cond = line[4:line.find(')')]
2395 if template_options.get(cond, default):
2396 return True
2397 else:
2398 return False
2399 elif line.strip().startswith('%'):
2400 parameter = line[line.find('(')+1:line.find(')')]
2401
2402 try:
2403 cond = self.cuts_parameter[parameter]
2404 except KeyError:
2405 return True
2406
2407
2408 if template_options.get(cond, default) or cond is True:
2409 return True
2410 else:
2411 return False
2412 else:
2413 return True
2414
2415
2416 - def write(self, output_file, template=None, python_template=False,
2417 write_hidden=False, template_options=None):
2418 """Write the run_card in output_file according to template
2419 (a path to a valid run_card)"""
2420
2421 to_write = set(self.user_set)
2422 written = set()
2423 if not template:
2424 raise Exception
2425 if not template_options:
2426 template_options = collections.defaultdict(str)
2427
2428
2429 write_block= []
2430 for b in self.blocks:
2431 name = b.name
2432
2433 if name not in self.display_block and \
2434 not any(f in self.user_set for f in b.fields):
2435 continue
2436 write_block.append(b.name)
2437
2438
2439 if python_template:
2440 text = open(template,'r').read()
2441 text = text.split('\n')
2442
2443 text = [l if not l.startswith('#IF') else l[l.find(')# ')+2:]
2444 for l in text if self.valid_line(l, template_options)]
2445 text ='\n'.join(text)
2446
2447 if python_template and not to_write:
2448 import string
2449 if self.blocks:
2450 text = string.Template(text)
2451 mapping = {}
2452 for b in self.blocks:
2453 if b.name in write_block:
2454 mapping[b.name] = b.template_on
2455 else:
2456 mapping[b.name] = b.template_off
2457 text = text.substitute(mapping)
2458
2459 if not self.list_parameter:
2460 text = text % self
2461 else:
2462 data = dict((key.lower(),value) for key, value in self.items())
2463 for name in self.list_parameter:
2464 if self.list_parameter[name] != str:
2465 data[name] = ', '.join(str(v) for v in data[name])
2466 else:
2467 data[name] = "['%s']" % "', '".join(str(v) for v in data[name])
2468 text = text % data
2469 else:
2470 text = ""
2471 for line in open(template,'r'):
2472 nline = line.split('#')[0]
2473 nline = nline.split('!')[0]
2474 comment = line[len(nline):]
2475 nline = nline.split('=')
2476 if python_template and nline[0].startswith('$'):
2477 block_name = nline[0][1:].strip()
2478 this_group = [b for b in self.blocks if b.name == block_name]
2479 if not this_group:
2480 logger.debug("block %s not defined", block_name)
2481 continue
2482 else:
2483 this_group = this_group[0]
2484 if block_name in write_block:
2485 text += this_group.template_on % self
2486 for name in this_group.fields:
2487 written.add(name)
2488 if name in to_write:
2489 to_write.remove(name)
2490 else:
2491 text += this_group.template_off % self
2492
2493 elif len(nline) != 2:
2494 text += line
2495 elif nline[1].strip() in self:
2496 name = nline[1].strip().lower()
2497 value = self[name]
2498 if name in self.list_parameter:
2499 if self.list_parameter[name] != str:
2500 value = ', '.join([str(v) for v in value])
2501 else:
2502 value = "['%s']" % "', '".join(str(v) for v in value)
2503 if python_template:
2504 text += line % {nline[1].strip():value, name:value}
2505 written.add(name)
2506 else:
2507 if not comment or comment[-1]!='\n':
2508 endline = '\n'
2509 else:
2510 endline = ''
2511 text += ' %s\t= %s %s%s' % (value, name, comment, endline)
2512 written.add(name)
2513
2514 if name in to_write:
2515 to_write.remove(name)
2516 else:
2517 logger.info('Adding missing parameter %s to current %s (with default value)',
2518 (name, self.filename))
2519 written.add(name)
2520 text += line
2521
2522 for b in self.blocks:
2523 if b.name not in write_block:
2524 continue
2525
2526 if all(f in written for f in b.fields):
2527 continue
2528
2529 to_add = []
2530 for line in b.template_on.split('\n'):
2531 nline = line.split('#')[0]
2532 nline = nline.split('!')[0]
2533 nline = nline.split('=')
2534 if len(nline) != 2:
2535 to_add.append(line)
2536 elif nline[1].strip() in self:
2537 name = nline[1].strip().lower()
2538 value = self[name]
2539 if name in self.list_parameter:
2540 value = ', '.join([str(v) for v in value])
2541 if name in written:
2542 continue
2543 else:
2544 to_add.append(line % {nline[1].strip():value, name:value})
2545 written.add(name)
2546
2547 if name in to_write:
2548 to_write.remove(name)
2549 else:
2550 raise Exception
2551
2552 if b.template_off in text:
2553 text = text.replace(b.template_off, '\n'.join(to_add))
2554 else:
2555 text += '\n'.join(to_add)
2556
2557 if to_write or write_hidden:
2558 text+="""#*********************************************************************
2559 # Additional hidden parameters
2560 #*********************************************************************
2561 """
2562 if write_hidden:
2563
2564
2565
2566 if python_template:
2567 written = written.union(set(re.findall('\%\((\w*)\)s', open(template,'r').read(), re.M)))
2568 to_write = to_write.union(set(self.hidden_param))
2569 to_write = to_write.difference(written)
2570
2571 for key in to_write:
2572 if key in self.system_only:
2573 continue
2574
2575 comment = self.comments.get(key,'hidden_parameter').replace('\n','\n#')
2576 text += ' %s\t= %s # %s\n' % (self[key], key, comment)
2577
2578 if isinstance(output_file, str):
2579 fsock = open(output_file,'w')
2580 fsock.write(text)
2581 fsock.close()
2582 else:
2583 output_file.write(text)
2584
2585
2586 - def get_default(self, name, default=None, log_level=None):
2615
2616
2617 @staticmethod
2666
2667
2668
2670 """check that parameter missing in the card are set to the expected value"""
2671
2672 for name, value in self.system_default.items():
2673 self.set(name, value, changeifuserset=False)
2674
2675
2676 for name in self.includepath[False]:
2677 to_bypass = self.hidden_param + list(self.legacy_parameter.keys())
2678 if name not in to_bypass:
2679 self.get_default(name, log_level=log_level)
2680
2681 for name in self.legacy_parameter:
2682 if self[name] != self.legacy_parameter[name]:
2683 logger.warning("The parameter %s is not supported anymore this parameter will be ignored." % name)
2684
2685 default_include_file = 'run_card.inc'
2686
2688 """update hidden system only parameter for the correct writtin in the
2689 include"""
2690 return
2691
2693 """Write the various include file in output_dir.
2694 The entry True of self.includepath will be written in run_card.inc
2695 The entry False will not be written anywhere"""
2696
2697
2698 self.check_validity()
2699
2700
2701 self.update_system_parameter_for_include()
2702
2703 for incname in self.includepath:
2704 if incname is True:
2705 pathinc = self.default_include_file
2706 elif incname is False:
2707 continue
2708 else:
2709 pathinc = incname
2710
2711 fsock = file_writers.FortranWriter(pjoin(output_dir,pathinc))
2712 for key in self.includepath[incname]:
2713
2714 if key in self.fortran_name:
2715 fortran_name = self.fortran_name[key]
2716 else:
2717 fortran_name = key
2718
2719
2720 value = self.get_default(key)
2721
2722
2723 if isinstance(value, list):
2724
2725
2726
2727 targettype = self.list_parameter[key]
2728 if targettype is bool:
2729 pass
2730 elif targettype is int:
2731 line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(len(value)))
2732 fsock.writelines(line)
2733 elif targettype is float:
2734 line = '%s(%s) = %s \n' % (fortran_name, 0, self.f77_formatting(float(len(value))))
2735 fsock.writelines(line)
2736
2737 for i,v in enumerate(value):
2738 line = '%s(%s) = %s \n' % (fortran_name, i+1, self.f77_formatting(v))
2739 fsock.writelines(line)
2740 elif isinstance(value, dict):
2741 for fortran_name, onevalue in value.items():
2742 line = '%s = %s \n' % (fortran_name, self.f77_formatting(onevalue))
2743 fsock.writelines(line)
2744 else:
2745 line = '%s = %s \n' % (fortran_name, self.f77_formatting(value))
2746 fsock.writelines(line)
2747 fsock.close()
2748
2749 @staticmethod
2751 """return the particle colliding pdg code"""
2752 if lpp in (1,2, -1,-2):
2753 return math.copysign(2212, lpp)
2754 elif lpp in (3,-3):
2755 return math.copysign(11, lpp)
2756 elif lpp == 0:
2757
2758 return 0
2759 else:
2760 return lpp
2761
2776
2778 if pdf == "lhapdf":
2779 lhaid = self["lhaid"]
2780 if isinstance(lhaid, list):
2781 return lhaid[0]
2782 else:
2783 return lhaid
2784 else:
2785 return {'none': 0,
2786 'cteq6_m':10000,'cteq6_l':10041,'cteq6l1':10042,
2787 'nn23lo':246800,'nn23lo1':247000,'nn23nlo':244800
2788 }[pdf]
2789
2792
2794 """remove all the cut"""
2795
2796 for name in self.cuts_parameter:
2797 targettype = type(self[name])
2798 if targettype == bool:
2799 self[name] = False
2800 if targettype == dict:
2801 self[name] = '{}'
2802 elif 'min' in name:
2803 self[name] = 0
2804 elif 'max' in name:
2805 self[name] = -1
2806 elif 'eta' in name:
2807 self[name] = -1
2808 else:
2809 self[name] = 0
2810
2812 """an object to handle in a nice way the run_card information"""
2813
2814 blocks = [
2815
2816 runblock(name='ion_pdf', fields=('nb_neutron1', 'nb_neutron2','nb_proton1','nb_proton2','mass_ion1', 'mass_ion2'),
2817 template_on=\
2818 """#*********************************************************************
2819 # Heavy ion PDF / rescaling of PDF *
2820 #*********************************************************************
2821 %(nb_proton1)s = nb_proton1 # number of proton for the first beam
2822 %(nb_neutron1)s = nb_neutron1 # number of neutron for the first beam
2823 %(mass_ion1)s = mass_ion1 # mass of the heavy ion (first beam)
2824 # Note that seting differently the two beams only work if you use
2825 # group_subprocess=False when generating your matrix-element
2826 %(nb_proton2)s = nb_proton2 # number of proton for the second beam
2827 %(nb_neutron2)s = nb_neutron2 # number of neutron for the second beam
2828 %(mass_ion2)s = mass_ion2 # mass of the heavy ion (second beam)
2829 """,
2830 template_off='# To see heavy ion options: type "update ion_pdf"'),
2831
2832
2833
2834 runblock(name='beam_pol', fields=('polbeam1','polbeam2'),
2835 template_on=\
2836 """#*********************************************************************
2837 # Beam polarization from -100 (left-handed) to 100 (right-handed) *
2838 #*********************************************************************
2839 %(polbeam1)s = polbeam1 ! beam polarization for beam 1
2840 %(polbeam2)s = polbeam2 ! beam polarization for beam 2
2841 """,
2842 template_off='# To see polarised beam options: type "update beam_pol"'),
2843
2844
2845 runblock(name='syscalc', fields=('sys_scalefact', 'sys_alpsfact','sys_matchscale','sys_pdf'),
2846 template_on=\
2847 """#**************************************
2848 # Parameter below of the systematics study
2849 # will be used by SysCalc (if installed)
2850 #**************************************
2851 #
2852 %(sys_scalefact)s = sys_scalefact # factorization/renormalization scale factor
2853 %(sys_alpsfact)s = sys_alpsfact # \alpha_s emission scale factors
2854 %(sys_matchscale)s = sys_matchscale # variation of merging scale
2855 # PDF sets and number of members (0 or none for all members).
2856 %(sys_pdf)s = sys_pdf # list of pdf sets. (errorset not valid for syscalc)
2857 # MSTW2008nlo68cl.LHgrid 1 = sys_pdf
2858 #
2859 """,
2860 template_off= '# Syscalc is deprecated but to see the associate options type\'update syscalc\''),
2861
2862
2863 runblock(name='ecut', fields=('ej','eb','ea','el','ejmax','ebmax','eamax','elmax','e_min_pdg','e_max_pdg'),
2864 template_on=\
2865 """#*********************************************************************
2866 # Minimum and maximum E's (in the center of mass frame) *
2867 #*********************************************************************
2868 %(ej)s = ej ! minimum E for the jets
2869 %(eb)s = eb ! minimum E for the b
2870 %(ea)s = ea ! minimum E for the photons
2871 %(el)s = el ! minimum E for the charged leptons
2872 %(ejmax)s = ejmax ! maximum E for the jets
2873 %(ebmax)s = ebmax ! maximum E for the b
2874 %(eamax)s = eamax ! maximum E for the photons
2875 %(elmax)s = elmax ! maximum E for the charged leptons
2876 %(e_min_pdg)s = e_min_pdg ! E cut for other particles (use pdg code). Applied on particle and anti-particle
2877 %(e_max_pdg)s = e_max_pdg ! E cut for other particles (syntax e.g. {6: 100, 25: 50})
2878 """,
2879 template_off= '#\n# For display option for energy cut in the partonic center of mass frame type \'update ecut\'\n#'),
2880
2881
2882 runblock(name='frame', fields=('me_frame'),
2883 template_on=\
2884 """#*********************************************************************
2885 # Frame where to evaluate the matrix-element (not the cut!) for polarization
2886 #*********************************************************************
2887 %(me_frame)s = me_frame ! list of particles to sum-up to define the rest-frame
2888 ! in which to evaluate the matrix-element
2889 ! [1,2] means the partonic center of mass
2890 """,
2891 template_off= ''),
2892
2893 runblock(name='MLM', fields=('ickkw','alpsfact','chcluster','asrwgtflavor','auto_ptj_mjj','xqcut'),
2894 template_on=\
2895 """#*********************************************************************
2896 # Matching parameter (MLM only)
2897 #*********************************************************************
2898 %(ickkw)s = ickkw ! 0 no matching, 1 MLM
2899 %(alpsfact)s = alpsfact ! scale factor for QCD emission vx
2900 %(chcluster)s = chcluster ! cluster only according to channel diag
2901 %(asrwgtflavor)s = asrwgtflavor ! highest quark flavor for a_s reweight
2902 %(auto_ptj_mjj)s = auto_ptj_mjj ! Automatic setting of ptj and mjj if xqcut >0
2903 ! (turn off for VBF and single top processes)
2904 %(xqcut)s = xqcut ! minimum kt jet measure between partons
2905 """,
2906 template_off='# To see MLM/CKKW merging options: type "update MLM" or "update CKKW"'),
2907
2908
2909 runblock(name='CKKW', fields=(),
2910 template_on=\
2911 """#***********************************************************************
2912 # Turn on either the ktdurham or ptlund cut to activate *
2913 # CKKW(L) merging with Pythia8 [arXiv:1410.3012, arXiv:1109.4829] *
2914 #***********************************************************************
2915 %(ktdurham)s = ktdurham
2916 %(dparameter)s = dparameter
2917 %(ptlund)s = ptlund
2918 %(pdgs_for_merging_cut)s = pdgs_for_merging_cut ! PDGs for two cuts above
2919 """,
2920 template_off=''),
2921
2922 ]
2923
2924
2926 """default value for the run_card.dat"""
2927
2928 self.add_param("run_tag", "tag_1", include=False)
2929 self.add_param("gridpack", False)
2930 self.add_param("time_of_flight", -1.0, include=False)
2931 self.add_param("nevents", 10000)
2932 self.add_param("iseed", 0)
2933 self.add_param("python_seed", -2, include=False, hidden=True, comment="controlling python seed [handling in particular the final unweighting].\n -1 means use default from random module.\n -2 means set to same value as iseed")
2934 self.add_param("lpp1", 1, fortran_name="lpp(1)", allowed=[-1,1,0,2,3,9, -2,-3,4,-4],
2935 comment='first beam energy distribution:\n 0: fixed energy\n 1: PDF from proton\n -1: PDF from anti-proton\n 2:photon from proton, 3:photon from electron, 4: photon from muon, 9: PLUGIN MODE')
2936 self.add_param("lpp2", 1, fortran_name="lpp(2)", allowed=[-1,1,0,2,3,9,4,-4],
2937 comment='first beam energy distribution:\n 0: fixed energy\n 1: PDF from proton\n -1: PDF from anti-proton\n 2:photon from proton, 3:photon from electron, 4: photon from muon, 9: PLUGIN MODE')
2938 self.add_param("ebeam1", 6500.0, fortran_name="ebeam(1)")
2939 self.add_param("ebeam2", 6500.0, fortran_name="ebeam(2)")
2940 self.add_param("polbeam1", 0.0, fortran_name="pb1", hidden=True,
2941 comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--")
2942 self.add_param("polbeam2", 0.0, fortran_name="pb2", hidden=True,
2943 comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--")
2944 self.add_param('nb_proton1', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(1)",
2945 comment='For heavy ion physics nb of proton in the ion (for both beam but if group_subprocess was False)')
2946 self.add_param('nb_proton2', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(2)",
2947 comment='For heavy ion physics nb of proton in the ion (used for beam 2 if group_subprocess was False)')
2948 self.add_param('nb_neutron1', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(1)",
2949 comment='For heavy ion physics nb of neutron in the ion (for both beam but if group_subprocess was False)')
2950 self.add_param('nb_neutron2', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(2)",
2951 comment='For heavy ion physics nb of neutron in the ion (of beam 2 if group_subprocess was False )')
2952 self.add_param('mass_ion1', -1.0, hidden=True, fortran_name="mass_ion(1)",
2953 allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'],
2954 comment='For heavy ion physics mass in GeV of the ion (of beam 1)')
2955 self.add_param('mass_ion2', -1.0, hidden=True, fortran_name="mass_ion(2)",
2956 allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'],
2957 comment='For heavy ion physics mass in GeV of the ion (of beam 2)')
2958
2959 self.add_param("pdlabel", "nn23lo1", allowed=['lhapdf', 'cteq6_m','cteq6_l', 'cteq6l1','nn23lo', 'nn23lo1', 'nn23nlo']),
2960 self.add_param("lhaid", 230000, hidden=True)
2961 self.add_param("fixed_ren_scale", False)
2962 self.add_param("fixed_fac_scale", False)
2963 self.add_param("scale", 91.1880)
2964 self.add_param("dsqrt_q2fact1", 91.1880, fortran_name="sf1")
2965 self.add_param("dsqrt_q2fact2", 91.1880, fortran_name="sf2")
2966 self.add_param("dynamical_scale_choice", -1, comment="\'-1\' is based on CKKW back clustering (following feynman diagram).\n \'1\' is the sum of transverse energy.\n '2' is HT (sum of the transverse mass)\n '3' is HT/2\n '4' is the center of mass energy",
2967 allowed=[-1,0,1,2,3,4])
2968
2969
2970 self.add_param("bias_module", 'None', include=False)
2971 self.add_param('bias_parameters', {'__type__':1.0}, include='BIAS/bias.inc')
2972
2973
2974 self.add_param("scalefact", 1.0)
2975 self.add_param("ickkw", 0, allowed=[0,1], hidden=True, comment="\'0\' for standard fixed order computation.\n\'1\' for MLM merging activates alphas and pdf re-weighting according to a kt clustering of the QCD radiation.")
2976 self.add_param("highestmult", 1, fortran_name="nhmult", hidden=True)
2977 self.add_param("ktscheme", 1, hidden=True)
2978 self.add_param("alpsfact", 1.0, hidden=True)
2979 self.add_param("chcluster", False, hidden=True)
2980 self.add_param("pdfwgt", True, hidden=True)
2981 self.add_param("asrwgtflavor", 5, hidden=True, comment = 'highest quark flavor for a_s reweighting in MLM')
2982 self.add_param("clusinfo", True, hidden=True)
2983
2984 self.add_param("lhe_version", 3.0, hidden=True)
2985 self.add_param("boost_event", "False", hidden=True, include=False, comment="allow to boost the full event. The boost put at rest the sume of 4-momenta of the particle selected by the filter defined here. example going to the higgs rest frame: lambda p: p.pid==25")
2986 self.add_param("me_frame", [1,2], hidden=True, include=False, comment="choose lorentz frame where to evaluate matrix-element [for non lorentz invariant matrix-element/polarization]:\n - 0: partonic center of mass\n - 1: Multi boson frame\n - 2 : (multi) scalar frame\n - 3 : user custom")
2987 self.add_param('frame_id', 6, system=True)
2988 self.add_param("event_norm", "average", allowed=['sum','average', 'unity'],
2989 include=False, sys_default='sum', hidden=True)
2990
2991 self.add_param("auto_ptj_mjj", True, hidden=True)
2992 self.add_param("bwcutoff", 15.0)
2993 self.add_param("cut_decays", False, cut='d')
2994 self.add_param("nhel", 0, include=False)
2995
2996 self.add_param("ptj", 20.0, cut='j')
2997 self.add_param("ptb", 0.0, cut='b')
2998 self.add_param("pta", 10.0, cut='a')
2999 self.add_param("ptl", 10.0, cut='l')
3000 self.add_param("misset", 0.0, cut='n')
3001 self.add_param("ptheavy", 0.0, cut='H', comment='this cut apply on particle heavier than 10 GeV')
3002 self.add_param("ptonium", 1.0, legacy=True)
3003 self.add_param("ptjmax", -1.0, cut='j')
3004 self.add_param("ptbmax", -1.0, cut='b')
3005 self.add_param("ptamax", -1.0, cut='a')
3006 self.add_param("ptlmax", -1.0, cut='l')
3007 self.add_param("missetmax", -1.0, cut='n')
3008
3009 self.add_param("ej", 0.0, cut='j', hidden=True)
3010 self.add_param("eb", 0.0, cut='b', hidden=True)
3011 self.add_param("ea", 0.0, cut='a', hidden=True)
3012 self.add_param("el", 0.0, cut='l', hidden=True)
3013 self.add_param("ejmax", -1.0, cut='j', hidden=True)
3014 self.add_param("ebmax", -1.0, cut='b', hidden=True)
3015 self.add_param("eamax", -1.0, cut='a', hidden=True)
3016 self.add_param("elmax", -1.0, cut='l', hidden=True)
3017
3018 self.add_param("etaj", 5.0, cut='j')
3019 self.add_param("etab", -1.0, cut='b')
3020 self.add_param("etaa", 2.5, cut='a')
3021 self.add_param("etal", 2.5, cut='l')
3022 self.add_param("etaonium", 0.6, legacy=True)
3023 self.add_param("etajmin", 0.0, cut='a')
3024 self.add_param("etabmin", 0.0, cut='b')
3025 self.add_param("etaamin", 0.0, cut='a')
3026 self.add_param("etalmin", 0.0, cut='l')
3027
3028 self.add_param("drjj", 0.4, cut='jj')
3029 self.add_param("drbb", 0.0, cut='bb')
3030 self.add_param("drll", 0.4, cut='ll')
3031 self.add_param("draa", 0.4, cut='aa')
3032 self.add_param("drbj", 0.0, cut='bj')
3033 self.add_param("draj", 0.4, cut='aj')
3034 self.add_param("drjl", 0.4, cut='jl')
3035 self.add_param("drab", 0.0, cut='ab')
3036 self.add_param("drbl", 0.0, cut='bl')
3037 self.add_param("dral", 0.4, cut='al')
3038 self.add_param("drjjmax", -1.0, cut='jj')
3039 self.add_param("drbbmax", -1.0, cut='bb')
3040 self.add_param("drllmax", -1.0, cut='ll')
3041 self.add_param("draamax", -1.0, cut='aa')
3042 self.add_param("drbjmax", -1.0, cut='bj')
3043 self.add_param("drajmax", -1.0, cut='aj')
3044 self.add_param("drjlmax", -1.0, cut='jl')
3045 self.add_param("drabmax", -1.0, cut='ab')
3046 self.add_param("drblmax", -1.0, cut='bl')
3047 self.add_param("dralmax", -1.0, cut='al')
3048
3049 self.add_param("mmjj", 0.0, cut='jj')
3050 self.add_param("mmbb", 0.0, cut='bb')
3051 self.add_param("mmaa", 0.0, cut='aa')
3052 self.add_param("mmll", 0.0, cut='ll')
3053 self.add_param("mmjjmax", -1.0, cut='jj')
3054 self.add_param("mmbbmax", -1.0, cut='bb')
3055 self.add_param("mmaamax", -1.0, cut='aa')
3056 self.add_param("mmllmax", -1.0, cut='ll')
3057 self.add_param("mmnl", 0.0, cut='LL')
3058 self.add_param("mmnlmax", -1.0, cut='LL')
3059
3060 self.add_param("ptllmin", 0.0, cut='ll')
3061 self.add_param("ptllmax", -1.0, cut='ll')
3062 self.add_param("xptj", 0.0, cut='jj')
3063 self.add_param("xptb", 0.0, cut='bb')
3064 self.add_param("xpta", 0.0, cut='aa')
3065 self.add_param("xptl", 0.0, cut='ll')
3066
3067 self.add_param("ptj1min", 0.0, cut='jj')
3068 self.add_param("ptj1max", -1.0, cut='jj')
3069 self.add_param("ptj2min", 0.0, cut='jj')
3070 self.add_param("ptj2max", -1.0, cut='jj')
3071 self.add_param("ptj3min", 0.0, cut='jjj')
3072 self.add_param("ptj3max", -1.0, cut='jjj')
3073 self.add_param("ptj4min", 0.0, cut='j'*4)
3074 self.add_param("ptj4max", -1.0, cut='j'*4)
3075 self.add_param("cutuse", 0, cut='jj')
3076
3077 self.add_param("ptl1min", 0.0, cut='l'*2)
3078 self.add_param("ptl1max", -1.0, cut='l'*2)
3079 self.add_param("ptl2min", 0.0, cut='l'*2)
3080 self.add_param("ptl2max", -1.0, cut='l'*2)
3081 self.add_param("ptl3min", 0.0, cut='l'*3)
3082 self.add_param("ptl3max", -1.0, cut='l'*3)
3083 self.add_param("ptl4min", 0.0, cut='l'*4)
3084 self.add_param("ptl4max", -1.0, cut='l'*4)
3085
3086 self.add_param("htjmin", 0.0, cut='j'*2)
3087 self.add_param("htjmax", -1.0, cut='j'*2)
3088 self.add_param("ihtmin", 0.0, cut='J'*2)
3089 self.add_param("ihtmax", -1.0, cut='J'*2)
3090 self.add_param("ht2min", 0.0, cut='J'*3)
3091 self.add_param("ht3min", 0.0, cut='J'*3)
3092 self.add_param("ht4min", 0.0, cut='J'*4)
3093 self.add_param("ht2max", -1.0, cut='J'*3)
3094 self.add_param("ht3max", -1.0, cut='J'*3)
3095 self.add_param("ht4max", -1.0, cut='J'*4)
3096
3097 self.add_param("ptgmin", 0.0, cut='aj')
3098 self.add_param("r0gamma", 0.4, hidden=True)
3099 self.add_param("xn", 1.0, hidden=True)
3100 self.add_param("epsgamma", 1.0, hidden=True)
3101 self.add_param("isoem", True, hidden=True)
3102 self.add_param("xetamin", 0.0, cut='jj')
3103 self.add_param("deltaeta", 0.0, cut='j'*2)
3104 self.add_param("ktdurham", -1.0, fortran_name="kt_durham", cut='j')
3105 self.add_param("dparameter", 0.4, fortran_name="d_parameter", cut='j')
3106 self.add_param("ptlund", -1.0, fortran_name="pt_lund", cut='j')
3107 self.add_param("pdgs_for_merging_cut", [21, 1, 2, 3, 4, 5, 6], hidden=True)
3108 self.add_param("maxjetflavor", 4)
3109 self.add_param("xqcut", 0.0, cut=True)
3110 self.add_param("use_syst", True)
3111 self.add_param('systematics_program', 'systematics', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics, syscalc')
3112 self.add_param('systematics_arguments', ['--mur=0.5,1,2', '--muf=0.5,1,2', '--pdf=errorset'], include=False, hidden=True, comment='Choose the argment to pass to the systematics command. like --mur=0.25,1,4. Look at the help of the systematics function for more details.')
3113
3114 self.add_param("sys_scalefact", "0.5 1 2", include=False, hidden=True)
3115 self.add_param("sys_alpsfact", "None", include=False, hidden=True)
3116 self.add_param("sys_matchscale", "auto", include=False, hidden=True)
3117 self.add_param("sys_pdf", "errorset", include=False, hidden=True)
3118 self.add_param("sys_scalecorrelation", -1, include=False, hidden=True)
3119
3120
3121 self.add_param('gridrun', False, hidden=True)
3122 self.add_param('fixed_couplings', True, hidden=True)
3123 self.add_param('mc_grouped_subproc', True, hidden=True)
3124 self.add_param('xmtcentral', 0.0, hidden=True, fortran_name="xmtc")
3125 self.add_param('d', 1.0, hidden=True)
3126 self.add_param('gseed', 0, hidden=True, include=False)
3127 self.add_param('issgridfile', '', hidden=True)
3128
3129 self.add_param('job_strategy', 0, hidden=True, include=False, allowed=[0,1,2], comment='see appendix of 1507.00020 (page 26)')
3130 self.add_param('hard_survey', 0, hidden=True, include=False, comment='force to have better estimate of the integral at survey for difficult mode like VBF')
3131 self.add_param("second_refine_treshold", 0.9, hidden=True, include=False, comment="set a treshold to bypass the use of a second refine. if the ratio of cross-section after survey by the one of the first refine is above the treshold, the second refine will not be done.")
3132 self.add_param('survey_splitting', -1, hidden=True, include=False, comment="for loop-induced control how many core are used at survey for the computation of a single iteration.")
3133 self.add_param('survey_nchannel_per_job', 2, hidden=True, include=False, comment="control how many Channel are integrated inside a single job on cluster/multicore")
3134 self.add_param('refine_evt_by_job', -1, hidden=True, include=False, comment="control the maximal number of events for the first iteration of the refine (larger means less jobs)")
3135 self.add_param('small_width_treatment', 1e-6, hidden=True, comment="generation where the width is below VALUE times mass will be replace by VALUE times mass for the computation. The cross-section will be corrected assuming NWA. Not used for loop-induced process")
3136
3137
3138
3139 self.add_param('pt_min_pdg',{'__type__':0.}, include=False, cut=True)
3140 self.add_param('pt_max_pdg',{'__type__':0.}, include=False, cut=True)
3141 self.add_param('E_min_pdg',{'__type__':0.}, include=False, hidden=True,cut=True)
3142 self.add_param('E_max_pdg',{'__type__':0.}, include=False, hidden=True,cut=True)
3143 self.add_param('eta_min_pdg',{'__type__':0.}, include=False,cut=True)
3144 self.add_param('eta_max_pdg',{'__type__':0.}, include=False,cut=True)
3145 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True)
3146 self.add_param('mxx_only_part_antipart', {'default':False}, include=False)
3147
3148 self.add_param('pdg_cut',[0], system=True)
3149 self.add_param('ptmin4pdg',[0.], system=True)
3150 self.add_param('ptmax4pdg',[-1.], system=True)
3151 self.add_param('Emin4pdg',[0.], system=True)
3152 self.add_param('Emax4pdg',[-1.], system=True)
3153 self.add_param('etamin4pdg',[0.], system=True)
3154 self.add_param('etamax4pdg',[-1.], system=True)
3155 self.add_param('mxxmin4pdg',[-1.], system=True)
3156 self.add_param('mxxpart_antipart', [False], system=True)
3157
3158
3159
3161 """ """
3162
3163 super(RunCardLO, self).check_validity()
3164
3165
3166
3167
3168 if 'nhel' not in self:
3169 raise InvalidRunCard("Parameter nhel is not defined in the run_card.")
3170 if self['nhel'] not in [1,0]:
3171 raise InvalidRunCard("Parameter nhel can only be '0' or '1', "+\
3172 "not %s." % self['nhel'])
3173 if int(self['maxjetflavor']) > 6:
3174 raise InvalidRunCard('maxjetflavor should be lower than 5! (6 is partly supported)')
3175
3176 if len(self['pdgs_for_merging_cut']) > 1000:
3177 raise InvalidRunCard("The number of elements in "+\
3178 "'pdgs_for_merging_cut' should not exceed 1000.")
3179
3180
3181 if self['ptgmin'] > 0:
3182 if self['pta'] > 0:
3183 logger.warning('pta cut discarded since photon isolation is used')
3184 self['pta'] = 0.0
3185 if self['draj'] > 0:
3186 logger.warning('draj cut discarded since photon isolation is used')
3187 self['draj'] = 0.0
3188
3189
3190 if self['gridrun']:
3191 self['iseed'] = self['gseed']
3192
3193
3194 if self['use_syst']:
3195 if self['scalefact'] != 1.0:
3196 logger.warning('Since use_syst=T, We change the value of \'scalefact\' to 1')
3197 self['scalefact'] = 1.0
3198
3199
3200 if self['ickkw'] > 0:
3201 if self['ickkw'] != 1:
3202 logger.critical('ickkw >1 is pure alpha and only partly implemented.')
3203 import madgraph.interface.extended_cmd as basic_cmd
3204 answer = basic_cmd.smart_input('Do you really want to continue', allow_arg=['y','n'], default='n')
3205 if answer !='y':
3206 raise InvalidRunCard('ickkw>1 is still in alpha')
3207 if self['use_syst']:
3208
3209 if self['alpsfact'] != 1.0:
3210 logger.warning('Since use_syst=T, We change the value of \'alpsfact\' to 1')
3211 self['alpsfact'] =1.0
3212 if self['maxjetflavor'] == 6:
3213 raise InvalidRunCard('maxjetflavor at 6 is NOT supported for matching!')
3214 if self['ickkw'] == 2:
3215
3216 self.get_default('highestmult', log_level=20)
3217 self.get_default('issgridfile', 'issudgrid.dat', log_level=20)
3218 if self['xqcut'] > 0:
3219 if self['ickkw'] == 0:
3220 logger.error('xqcut>0 but ickkw=0. Potentially not fully consistent setup. Be carefull')
3221 time.sleep(5)
3222 if self['drjj'] != 0:
3223 if 'drjj' in self.user_set:
3224 logger.warning('Since icckw>0, We change the value of \'drjj\' to 0')
3225 self['drjj'] = 0
3226 if self['drjl'] != 0:
3227 if 'drjl' in self.user_set:
3228 logger.warning('Since icckw>0, We change the value of \'drjl\' to 0')
3229 self['drjl'] = 0
3230 if not self['auto_ptj_mjj']:
3231 if self['mmjj'] > self['xqcut']:
3232 logger.warning('mmjj > xqcut (and auto_ptj_mjj = F). MMJJ set to 0')
3233 self['mmjj'] = 0.0
3234
3235
3236 if self['pdlabel'] == 'lhapdf':
3237
3238 self.get_default('lhaid', log_level=20)
3239
3240
3241 if self['lpp1'] not in [1,2]:
3242 if self['nb_proton1'] !=1 or self['nb_neutron1'] !=0:
3243 raise InvalidRunCard( "Heavy ion mode is only supported for lpp1=1/2")
3244 if self['lpp2'] not in [1,2]:
3245 if self['nb_proton2'] !=1 or self['nb_neutron2'] !=0:
3246 raise InvalidRunCard( "Heavy ion mode is only supported for lpp2=1/2")
3247
3248
3249 for i in [1,2]:
3250 if abs(self['lpp%s' % i ]) in [3,4] and self['dsqrt_q2fact%s'%i] == 91.188:
3251 logger.warning("Photon from lepton are using fixed scale value of muf [dsqrt_q2fact%s] as the cut of the EPA. Looks like you kept the default value (Mz). Is this really the cut-off of the EPA that you want to use?" % i)
3252 time.sleep(5)
3253
3254 if abs(self['lpp%s' % i ]) == 2 and self['dsqrt_q2fact%s'%i] == 91.188:
3255 logger.warning("Since 2.7.1 Photon from proton are using fixed scale value of muf [dsqrt_q2fact%s] as the cut of the Improved Weizsaecker-Williams formula. Please edit it accordingly." % i)
3256 time.sleep(5)
3257
3258
3259 if abs(self['lpp1']) in [2, 3,4] and abs(self['lpp2']) in [2, 3,4] and not self['fixed_fac_scale']:
3260 raise InvalidRunCard("Having both beam in elastic photon mode requires fixec_fac_scale to be on True [since this is use as cutoff]")
3261
3262
3264
3265
3266 self['frame_id'] = sum(2**(n) for n in self['me_frame'])
3267
3268
3269 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys()) +
3270 list(self['e_min_pdg'].keys()) +list(self['e_max_pdg'].keys()) +
3271 list(self['eta_min_pdg'].keys()) +list(self['eta_max_pdg'].keys())+
3272 list(self['mxx_min_pdg'].keys()) + list(self['mxx_only_part_antipart'].keys()))
3273 pdg_to_cut.discard('__type__')
3274 pdg_to_cut.discard('default')
3275 if len(pdg_to_cut)>25:
3276 raise Exception("Maximum 25 different pdgs are allowed for pdg specific cut")
3277
3278 if any(int(pdg)<0 for pdg in pdg_to_cut):
3279 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
3280 raise MadGraph5Error('Some PDG specific cuts are defined with negative pdg code')
3281
3282
3283 if any(pdg in pdg_to_cut for pdg in [1,2,3,4,5,21,22,11,13,15]):
3284 raise Exception("Can not use PDG related cut for light quark/b quark/lepton/gluon/photon")
3285
3286 if pdg_to_cut:
3287 self['pdg_cut'] = list(pdg_to_cut)
3288 self['ptmin4pdg'] = []
3289 self['Emin4pdg'] = []
3290 self['etamin4pdg'] =[]
3291 self['ptmax4pdg'] = []
3292 self['Emax4pdg'] = []
3293 self['etamax4pdg'] =[]
3294 self['mxxmin4pdg'] =[]
3295 self['mxxpart_antipart'] = []
3296 for pdg in self['pdg_cut']:
3297 for var in ['pt','e','eta', 'Mxx']:
3298 for minmax in ['min', 'max']:
3299 if var in ['Mxx'] and minmax =='max':
3300 continue
3301 new_var = '%s%s4pdg' % (var, minmax)
3302 old_var = '%s_%s_pdg' % (var, minmax)
3303 default = 0. if minmax=='min' else -1.
3304 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3305
3306 old_var = 'mxx_only_part_antipart'
3307 new_var = 'mxxpart_antipart'
3308 if 'default' in self[old_var]:
3309 default = self[old_var]['default']
3310 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3311 else:
3312 if str(pdg) not in self[old_var]:
3313 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
3314 self[new_var].append(self[old_var][str(pdg)])
3315 else:
3316 self['pdg_cut'] = [0]
3317 self['ptmin4pdg'] = [0.]
3318 self['Emin4pdg'] = [0.]
3319 self['etamin4pdg'] =[0.]
3320 self['ptmax4pdg'] = [-1.]
3321 self['Emax4pdg'] = [-1.]
3322 self['etamax4pdg'] =[-1.]
3323 self['mxxmin4pdg'] =[0.]
3324 self['mxxpart_antipart'] = [False]
3325
3326
3327
3329 """Rules
3330 process 1->N all cut set on off.
3331 loop_induced -> MC over helicity
3332 e+ e- beam -> lpp:0 ebeam:500
3333 p p beam -> set maxjetflavor automatically
3334 more than one multiplicity: ickkw=1 xqcut=30 use_syst=F
3335 """
3336
3337 if proc_characteristic['loop_induced']:
3338 self['nhel'] = 1
3339 self['pdgs_for_merging_cut'] = proc_characteristic['colored_pdgs']
3340
3341 if proc_characteristic['ninitial'] == 1:
3342
3343 self.remove_all_cut()
3344 self['use_syst'] = False
3345 else:
3346
3347
3348 beam_id = set()
3349 beam_id_split = [set(), set()]
3350 for proc in proc_def:
3351 for oneproc in proc:
3352 for i,leg in enumerate(oneproc['legs']):
3353 if not leg['state']:
3354 beam_id_split[i].add(leg['id'])
3355 beam_id.add(leg['id'])
3356
3357 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3358 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
3359 self['maxjetflavor'] = maxjetflavor
3360 self['asrwgtflavor'] = maxjetflavor
3361
3362 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3363
3364 if any(id in beam_id for id in [11,-11,13,-13]):
3365 self.display_block.append('beam_pol')
3366 if any(id in beam_id_split[0] for id in [11,-11,13,-13]):
3367 self['lpp1'] = 0
3368 self['lpp2'] = 1
3369 self['ebeam1'] = '1k'
3370 self['ebeam2'] = '6500'
3371 else:
3372 self['lpp1'] = 1
3373 self['lpp2'] = 0
3374 self['ebeam1'] = '6500'
3375 self['ebeam2'] = '1k'
3376
3377 elif any(id in beam_id for id in [11,-11,13,-13]):
3378 self['lpp1'] = 0
3379 self['lpp2'] = 0
3380 self['ebeam1'] = 500
3381 self['ebeam2'] = 500
3382 self['use_syst'] = False
3383 if set([ abs(i) for i in beam_id_split[0]]) == set([ abs(i) for i in beam_id_split[1]]):
3384 self.display_block.append('ecut')
3385 self.display_block.append('beam_pol')
3386 else:
3387 self['lpp1'] = 0
3388 self['lpp2'] = 0
3389 self['use_syst'] = False
3390 self.display_block.append('beam_pol')
3391 self.display_block.append('ecut')
3392
3393
3394 if any(id in beam_id for id in [12,-12,14,-14,16,-16]):
3395 self.display_block.append('beam_pol')
3396 if any(id in beam_id_split[0] for id in [12,14,16]):
3397 self['lpp1'] = 0
3398 self['ebeam1'] = '1k'
3399 self['polbeam1'] = -100
3400 if not all(id in [12,14,16] for id in beam_id_split[0]):
3401 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1]. %s')
3402 elif any(id in beam_id_split[0] for id in [-12,-14,-16]):
3403 self['lpp1'] = 0
3404 self['ebeam1'] = '1k'
3405 self['polbeam1'] = 100
3406 if not all(id in [-12,-14,-16] for id in beam_id_split[0]):
3407 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam1].')
3408 if any(id in beam_id_split[1] for id in [12,14,16]):
3409 self['lpp2'] = 0
3410 self['ebeam2'] = '1k'
3411 self['polbeam2'] = -100
3412 if not all(id in [12,14,16] for id in beam_id_split[1]):
3413 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].')
3414 if any(id in beam_id_split[1] for id in [-12,-14,-16]):
3415 self['lpp2'] = 0
3416 self['ebeam2'] = '1k'
3417 self['polbeam2'] = 100
3418 if not all(id in [-12,-14,-16] for id in beam_id_split[1]):
3419 logger.warning('Issue with default beam setup of neutrino in the run_card. Please check it up [polbeam2].')
3420
3421
3422 min_particle = 99
3423 max_particle = 0
3424 for proc in proc_def:
3425 min_particle = min(len(proc[0]['legs']), min_particle)
3426 max_particle = max(len(proc[0]['legs']), max_particle)
3427 if min_particle != max_particle:
3428
3429 for procmin in proc_def:
3430 if len(procmin[0]['legs']) != min_particle:
3431 continue
3432 else:
3433 idsmin = [l['id'] for l in procmin[0]['legs']]
3434 break
3435 matching = False
3436 for procmax in proc_def:
3437 if len(procmax[0]['legs']) != max_particle:
3438 continue
3439 idsmax = [l['id'] for l in procmax[0]['legs']]
3440 for i in idsmin:
3441 if i not in idsmax:
3442 continue
3443 else:
3444 idsmax.remove(i)
3445 for j in idsmax:
3446 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
3447 break
3448 else:
3449
3450 matching=True
3451 break
3452
3453 if matching:
3454 self['ickkw'] = 1
3455 self['xqcut'] = 30
3456
3457 self['drjj'] = 0
3458 self['drjl'] = 0
3459 self['sys_alpsfact'] = "0.5 1 2"
3460 self['systematics_arguments'].append('--alps=0.5,1,2')
3461 self.display_block.append('MLM')
3462 self.display_block.append('CKKW')
3463
3464
3465
3466 no_systematics = False
3467 for proc in proc_def:
3468 for oneproc in proc:
3469 if '^2' in oneproc.nice_string():
3470 no_systematics = True
3471 break
3472 else:
3473 continue
3474 break
3475
3476
3477 if no_systematics:
3478 self['use_syst'] = False
3479 self['systematics_program'] = 'none'
3480
3481
3482
3483 for plist in proc_def:
3484 for proc in plist:
3485 for l in proc.get('legs') + proc.get('legs_with_decays'):
3486 if l.get('polarization'):
3487 model = proc.get('model')
3488 particle = model.get_particle(l.get('id'))
3489 if particle.get('mass').lower() != 'zero':
3490 self.display_block.append('frame')
3491 break
3492 else:
3493 continue
3494 break
3495 else:
3496 continue
3497 break
3498
3499 if 'MLM' in proc_characteristic['limitations']:
3500 if self['dynamical_scale_choice'] == -1:
3501 self['dynamical_scale_choice'] = 3
3502 if self['ickkw'] == 1:
3503 logger.critical("MLM matching/merging not compatible with the model! You need to use another method to remove the double counting!")
3504 self['ickkw'] = 0
3505
3506
3507
3508 cut_class = collections.defaultdict(int)
3509 for proc in proc_def:
3510 for oneproc in proc:
3511 one_proc_cut = collections.defaultdict(int)
3512 ids = oneproc.get_final_ids_after_decay()
3513 if oneproc['decay_chains']:
3514 cut_class['d'] = 1
3515 for pdg in ids:
3516 if pdg == 22:
3517 one_proc_cut['a'] +=1
3518 elif abs(pdg) <= self['maxjetflavor']:
3519 one_proc_cut['j'] += 1
3520 one_proc_cut['J'] += 1
3521 elif abs(pdg) <= 5:
3522 one_proc_cut['b'] += 1
3523 one_proc_cut['J'] += 1
3524 elif abs(pdg) in [11,13,15]:
3525 one_proc_cut['l'] += 1
3526 one_proc_cut['L'] += 1
3527 elif abs(pdg) in [12,14,16]:
3528 one_proc_cut['n'] += 1
3529 one_proc_cut['L'] += 1
3530 elif str(oneproc.get('model').get_particle(pdg)['mass']) != 'ZERO':
3531 one_proc_cut['H'] += 1
3532
3533 for key, nb in one_proc_cut.items():
3534 cut_class[key] = max(cut_class[key], nb)
3535 self.cut_class = dict(cut_class)
3536 self.cut_class[''] = True
3537
3538 - def write(self, output_file, template=None, python_template=False,
3539 **opt):
3540 """Write the run_card in output_file according to template
3541 (a path to a valid run_card)"""
3542
3543 if not template:
3544 if not MADEVENT:
3545 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
3546 'run_card.dat')
3547 python_template = True
3548 else:
3549 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
3550 python_template = False
3551
3552
3553 hid_lines = {'default':True}
3554 if isinstance(output_file, str):
3555 if 'default' in output_file:
3556 if self.cut_class:
3557 hid_lines['default'] = False
3558 for key in self.cut_class:
3559 nb = self.cut_class[key]
3560 for i in range(1,nb+1):
3561 hid_lines[key*i] = True
3562 for k1,k2 in ['bj', 'bl', 'al', 'jl', 'ab', 'aj']:
3563 if self.cut_class.get(k1) and self.cut_class.get(k2):
3564 hid_lines[k1+k2] = True
3565
3566 super(RunCardLO, self).write(output_file, template=template,
3567 python_template=python_template,
3568 template_options=hid_lines,
3569 **opt)
3570
3574
3576 """ A class to store a MadAnalysis5 card. Very basic since it is basically
3577 free format."""
3578
3579 _MG5aMC_escape_tag = '@MG5aMC'
3580
3581 _default_hadron_inputs = ['*.hepmc', '*.hep', '*.stdhep', '*.lhco','*.root']
3582 _default_parton_inputs = ['*.lhe']
3583 _skip_analysis = False
3584
3585 @classmethod
3587 """ Checks from the type of an event file whether it can be reconstructed or not."""
3588 return not (file_path.endswith('.lhco') or file_path.endswith('.lhco.gz') or \
3589 file_path.endswith('.root') or file_path.endswith('.root.gz'))
3590
3591 @classmethod
3593 """ A method returning the structure of an empty analysis """
3594 return {'commands':[],
3595 'reconstructions':[]}
3596
3597 @classmethod
3599 """ A method returning the structure of an empty reconstruction """
3600 return {'commands':[],
3601 'reco_output':'lhe'}
3602
3604 """define the default value"""
3605 self['mode'] = 'parton'
3606 self['inputs'] = []
3607
3608 self['stdout_lvl'] = None
3609
3610
3611
3612
3613
3614
3615
3616 self['analyses'] = {}
3617
3618
3619 self['recasting'] = {'commands':[],'card':[]}
3620
3621
3622 self['reconstruction'] = {'lhco_input':
3623 MadAnalysis5Card.empty_reconstruction(),
3624 'root_input':
3625 MadAnalysis5Card.empty_reconstruction()}
3626 self['reconstruction']['lhco_input']['reco_output']='lhco'
3627 self['reconstruction']['root_input']['reco_output']='root'
3628
3629
3630 self['order'] = []
3631
3632 - def __init__(self, finput=None,mode=None):
3633 if isinstance(finput, self.__class__):
3634 dict.__init__(self, finput)
3635 assert list(finput.__dict__.keys())
3636 for key in finput.__dict__:
3637 setattr(self, key, copy.copy(getattr(finput, key)) )
3638 return
3639 else:
3640 dict.__init__(self)
3641
3642
3643 self.default_setup()
3644 if not mode is None:
3645 self['mode']=mode
3646
3647
3648 if isinstance(finput, (file, str, StringIO.StringIO)):
3649 self.read(finput, mode=mode)
3650
3651 - def read(self, input, mode=None):
3652 """ Read an MA5 card"""
3653
3654 if mode not in [None,'parton','hadron']:
3655 raise MadGraph5Error('A MadAnalysis5Card can be read online the modes'+
3656 "'parton' or 'hadron'")
3657 card_mode = mode
3658
3659 if isinstance(input, (file, StringIO.StringIO)):
3660 input_stream = input
3661 elif isinstance(input, str):
3662 if not os.path.isfile(input):
3663 raise InvalidMadAnalysis5Card("Cannot read the MadAnalysis5 card."+\
3664 "File '%s' not found."%input)
3665 if mode is None and 'hadron' in input:
3666 card_mode = 'hadron'
3667 input_stream = open(input,'r')
3668 else:
3669 raise MadGraph5Error('Incorrect input for the read function of'+\
3670 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(input)))
3671
3672
3673 self.__init__()
3674 current_name = 'default'
3675 current_type = 'analyses'
3676 for line in input_stream:
3677
3678 if line.startswith('#'):
3679 continue
3680 if line.endswith('\n'):
3681 line = line[:-1]
3682 if line.strip()=='':
3683 continue
3684 if line.startswith(self._MG5aMC_escape_tag):
3685 try:
3686 option,value = line[len(self._MG5aMC_escape_tag):].split('=')
3687 value = value.strip()
3688 except ValueError:
3689 option = line[len(self._MG5aMC_escape_tag):]
3690 option = option.strip()
3691
3692 if option=='inputs':
3693 self['inputs'].extend([v.strip() for v in value.split(',')])
3694
3695 elif option == 'skip_analysis':
3696 self._skip_analysis = True
3697
3698 elif option=='stdout_lvl':
3699 try:
3700 self['stdout_lvl']=int(value)
3701 except ValueError:
3702 try:
3703 self['stdout_lvl']=eval(value)
3704 except:
3705 try:
3706 self['stdout_lvl']=eval('logging.%s'%value)
3707 except:
3708 raise InvalidMadAnalysis5Card(
3709 "MA5 output level specification '%s' is incorrect."%str(value))
3710
3711 elif option=='analysis_name':
3712 current_type = 'analyses'
3713 current_name = value
3714 if current_name in self[current_type]:
3715 raise InvalidMadAnalysis5Card(
3716 "Analysis '%s' already defined in MadAnalysis5 card"%current_name)
3717 else:
3718 self[current_type][current_name] = MadAnalysis5Card.empty_analysis()
3719
3720 elif option=='set_reconstructions':
3721 try:
3722 reconstructions = eval(value)
3723 if not isinstance(reconstructions, list):
3724 raise
3725 except:
3726 raise InvalidMadAnalysis5Card("List of reconstructions"+\
3727 " '%s' could not be parsed in MadAnalysis5 card."%value)
3728 if current_type!='analyses' and current_name not in self[current_type]:
3729 raise InvalidMadAnalysis5Card("A list of reconstructions"+\
3730 "can only be defined in the context of an "+\
3731 "analysis in a MadAnalysis5 card.")
3732 self[current_type][current_name]['reconstructions']=reconstructions
3733 continue
3734
3735 elif option=='reconstruction_name':
3736 current_type = 'reconstruction'
3737 current_name = value
3738 if current_name in self[current_type]:
3739 raise InvalidMadAnalysis5Card(
3740 "Reconstruction '%s' already defined in MadAnalysis5 hadron card"%current_name)
3741 else:
3742 self[current_type][current_name] = MadAnalysis5Card.empty_reconstruction()
3743
3744 elif option=='reco_output':
3745 if current_type!='reconstruction' or current_name not in \
3746 self['reconstruction']:
3747 raise InvalidMadAnalysis5Card(
3748 "Option '%s' is only available within the definition of a reconstruction"%option)
3749 if not value.lower() in ['lhe','root']:
3750 raise InvalidMadAnalysis5Card(
3751 "Option '%s' can only take the values 'lhe' or 'root'"%option)
3752 self['reconstruction'][current_name]['reco_output'] = value.lower()
3753
3754 elif option.startswith('recasting'):
3755 current_type = 'recasting'
3756 try:
3757 current_name = option.split('_')[1]
3758 except:
3759 raise InvalidMadAnalysis5Card('Malformed MA5 recasting option %s.'%option)
3760 if len(self['recasting'][current_name])>0:
3761 raise InvalidMadAnalysis5Card(
3762 "Only one recasting can be defined in MadAnalysis5 hadron card")
3763
3764 else:
3765 raise InvalidMadAnalysis5Card(
3766 "Unreckognized MG5aMC instruction in MadAnalysis5 card: '%s'"%option)
3767
3768 if option in ['analysis_name','reconstruction_name'] or \
3769 option.startswith('recasting'):
3770 self['order'].append((current_type,current_name))
3771 continue
3772
3773
3774
3775 if current_name == 'default' and current_type == 'analyses' and\
3776 'default' not in self['analyses']:
3777 self['analyses']['default'] = MadAnalysis5Card.empty_analysis()
3778 self['order'].append(('analyses','default'))
3779
3780 if current_type in ['recasting']:
3781 self[current_type][current_name].append(line)
3782 elif current_type in ['reconstruction']:
3783 self[current_type][current_name]['commands'].append(line)
3784 elif current_type in ['analyses']:
3785 self[current_type][current_name]['commands'].append(line)
3786
3787 if 'reconstruction' in self['analyses'] or len(self['recasting']['card'])>0:
3788 if mode=='parton':
3789 raise InvalidMadAnalysis5Card(
3790 "A parton MadAnalysis5 card cannot specify a recombination or recasting.")
3791 card_mode = 'hadron'
3792 elif mode is None:
3793 card_mode = 'parton'
3794
3795 self['mode'] = card_mode
3796 if self['inputs'] == []:
3797 if self['mode']=='hadron':
3798 self['inputs'] = self._default_hadron_inputs
3799 else:
3800 self['inputs'] = self._default_parton_inputs
3801
3802
3803
3804 if self['mode']=='hadron':
3805 for analysis_name, analysis in self['analyses'].items():
3806 if len(analysis['reconstructions'])==0:
3807 raise InvalidMadAnalysis5Card('Hadron-level analysis '+\
3808 "'%s' is not specified any reconstruction(s)."%analysis_name)
3809 if any(reco not in self['reconstruction'] for reco in \
3810 analysis['reconstructions']):
3811 raise InvalidMadAnalysis5Card('A reconstructions specified in'+\
3812 " analysis '%s' is not defined."%analysis_name)
3813
3814 - def write(self, output):
3815 """ Write an MA5 card."""
3816
3817 if isinstance(output, (file, StringIO.StringIO)):
3818 output_stream = output
3819 elif isinstance(output, str):
3820 output_stream = open(output,'w')
3821 else:
3822 raise MadGraph5Error('Incorrect input for the write function of'+\
3823 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(output)))
3824
3825 output_lines = []
3826 if self._skip_analysis:
3827 output_lines.append('%s skip_analysis'%self._MG5aMC_escape_tag)
3828 output_lines.append('%s inputs = %s'%(self._MG5aMC_escape_tag,','.join(self['inputs'])))
3829 if not self['stdout_lvl'] is None:
3830 output_lines.append('%s stdout_lvl=%s'%(self._MG5aMC_escape_tag,self['stdout_lvl']))
3831 for definition_type, name in self['order']:
3832
3833 if definition_type=='analyses':
3834 output_lines.append('%s analysis_name = %s'%(self._MG5aMC_escape_tag,name))
3835 output_lines.append('%s set_reconstructions = %s'%(self._MG5aMC_escape_tag,
3836 str(self['analyses'][name]['reconstructions'])))
3837 elif definition_type=='reconstruction':
3838 output_lines.append('%s reconstruction_name = %s'%(self._MG5aMC_escape_tag,name))
3839 elif definition_type=='recasting':
3840 output_lines.append('%s recasting_%s'%(self._MG5aMC_escape_tag,name))
3841
3842 if definition_type in ['recasting']:
3843 output_lines.extend(self[definition_type][name])
3844 elif definition_type in ['reconstruction']:
3845 output_lines.append('%s reco_output = %s'%(self._MG5aMC_escape_tag,
3846 self[definition_type][name]['reco_output']))
3847 output_lines.extend(self[definition_type][name]['commands'])
3848 elif definition_type in ['analyses']:
3849 output_lines.extend(self[definition_type][name]['commands'])
3850
3851 output_stream.write('\n'.join(output_lines))
3852
3853 return
3854
3855 - def get_MA5_cmds(self, inputs_arg, submit_folder, run_dir_path=None,
3856 UFO_model_path=None, run_tag=''):
3857 """ Returns a list of tuples ('AnalysisTag',['commands']) specifying
3858 the commands of the MadAnalysis runs required from this card.
3859 At parton-level, the number of such commands is the number of analysis
3860 asked for. In the future, the idea is that the entire card can be
3861 processed in one go from MA5 directly."""
3862
3863 if isinstance(inputs_arg, list):
3864 inputs = inputs_arg
3865 elif isinstance(inputs_arg, str):
3866 inputs = [inputs_arg]
3867 else:
3868 raise MadGraph5Error("The function 'get_MA5_cmds' can only take "+\
3869 " a string or a list for the argument 'inputs_arg'")
3870
3871 if len(inputs)==0:
3872 raise MadGraph5Error("The function 'get_MA5_cmds' must have "+\
3873 " at least one input specified'")
3874
3875 if run_dir_path is None:
3876 run_dir_path = os.path.dirname(inputs_arg)
3877
3878 cmds_list = []
3879
3880 UFO_load = []
3881
3882 if UFO_model_path:
3883 UFO_load.append('import %s'%UFO_model_path)
3884
3885 def get_import(input, type=None):
3886 """ Generates the MA5 import commands for that event file. """
3887 dataset_name = os.path.basename(input).split('.')[0]
3888 res = ['import %s as %s'%(input, dataset_name)]
3889 if not type is None:
3890 res.append('set %s.type = %s'%(dataset_name, type))
3891 return res
3892
3893 fifo_status = {'warned_fifo':False,'fifo_used_up':False}
3894 def warn_fifo(input):
3895 if not input.endswith('.fifo'):
3896 return False
3897 if not fifo_status['fifo_used_up']:
3898 fifo_status['fifo_used_up'] = True
3899 return False
3900 else:
3901 if not fifo_status['warned_fifo']:
3902 logger.warning('Only the first MA5 analysis/reconstructions can be run on a fifo. Subsequent runs will skip fifo inputs.')
3903 fifo_status['warned_fifo'] = True
3904 return True
3905
3906
3907 inputs_load = []
3908 for input in inputs:
3909 inputs_load.extend(get_import(input))
3910
3911 submit_command = 'submit %s'%submit_folder+'_%s'
3912
3913
3914
3915
3916 reconstruction_outputs = {
3917 'lhco_input':[f for f in inputs if
3918 f.endswith('.lhco') or f.endswith('.lhco.gz')],
3919 'root_input':[f for f in inputs if
3920 f.endswith('.root') or f.endswith('.root.gz')]}
3921
3922
3923 recasting_card_path = pjoin(run_dir_path,
3924 '_'.join([run_tag,os.path.basename(submit_folder),'recasting_card.dat']))
3925
3926
3927 for definition_type, name in self['order']:
3928 if definition_type == 'reconstruction':
3929 analysis_cmds = list(self['reconstruction'][name]['commands'])
3930 reco_outputs = []
3931 for i_input, input in enumerate(inputs):
3932
3933 if not MadAnalysis5Card.events_can_be_reconstructed(input):
3934 continue
3935
3936 if warn_fifo(input):
3937 continue
3938 analysis_cmds.append('import %s as reco_events'%input)
3939 if self['reconstruction'][name]['reco_output']=='lhe':
3940 reco_outputs.append('%s_%s.lhe.gz'%(os.path.basename(
3941 input).replace('_events','').split('.')[0],name))
3942 analysis_cmds.append('set main.outputfile=%s'%reco_outputs[-1])
3943 elif self['reconstruction'][name]['reco_output']=='root':
3944 reco_outputs.append('%s_%s.root'%(os.path.basename(
3945 input).replace('_events','').split('.')[0],name))
3946 analysis_cmds.append('set main.fastsim.rootfile=%s'%reco_outputs[-1])
3947 analysis_cmds.append(
3948 submit_command%('reco_%s_%d'%(name,i_input+1)))
3949 analysis_cmds.append('remove reco_events')
3950
3951 reconstruction_outputs[name]= [pjoin(run_dir_path,rec_out)
3952 for rec_out in reco_outputs]
3953 if len(reco_outputs)>0:
3954 cmds_list.append(('_reco_%s'%name,analysis_cmds))
3955
3956 elif definition_type == 'analyses':
3957 if self['mode']=='parton':
3958 cmds_list.append( (name, UFO_load+inputs_load+
3959 self['analyses'][name]['commands']+[submit_command%name]) )
3960 elif self['mode']=='hadron':
3961
3962 for reco in self['analyses'][name]['reconstructions']+\
3963 ['lhco_input','root_input']:
3964 if len(reconstruction_outputs[reco])==0:
3965 continue
3966 if self['reconstruction'][reco]['reco_output']=='lhe':
3967
3968 analysis_cmds = ['set main.mode = parton']
3969 else:
3970 analysis_cmds = []
3971 analysis_cmds.extend(sum([get_import(rec_out) for
3972 rec_out in reconstruction_outputs[reco]],[]))
3973 analysis_cmds.extend(self['analyses'][name]['commands'])
3974 analysis_cmds.append(submit_command%('%s_%s'%(name,reco)))
3975 cmds_list.append( ('%s_%s'%(name,reco),analysis_cmds) )
3976
3977 elif definition_type == 'recasting':
3978 if len(self['recasting']['card'])==0:
3979 continue
3980 if name == 'card':
3981
3982 open(recasting_card_path,'w').write('\n'.join(self['recasting']['card']))
3983 if name == 'commands':
3984 recasting_cmds = list(self['recasting']['commands'])
3985
3986 n_inputs = 0
3987 for input in inputs:
3988 if not MadAnalysis5Card.events_can_be_reconstructed(input):
3989 continue
3990
3991 if warn_fifo(input):
3992 continue
3993 recasting_cmds.extend(get_import(input,'signal'))
3994 n_inputs += 1
3995
3996 recasting_cmds.append('set main.recast.card_path=%s'%recasting_card_path)
3997 recasting_cmds.append(submit_command%'Recasting')
3998 if n_inputs>0:
3999 cmds_list.append( ('Recasting',recasting_cmds))
4000
4001 return cmds_list
4002
4004 """A class object for the run_card for a (aMC@)NLO pocess"""
4005
4007 """define the default value"""
4008
4009 self.add_param('run_tag', 'tag_1', include=False)
4010 self.add_param('nevents', 10000)
4011 self.add_param('req_acc', -1.0, include=False)
4012 self.add_param('nevt_job', -1, include=False)
4013 self.add_param('event_norm', 'average')
4014
4015 self.add_param('req_acc_fo', 0.01, include=False)
4016 self.add_param('npoints_fo_grid', 5000, include=False)
4017 self.add_param('niters_fo_grid', 4, include=False)
4018 self.add_param('npoints_fo', 10000, include=False)
4019 self.add_param('niters_fo', 6, include=False)
4020
4021 self.add_param('iseed', 0)
4022 self.add_param('lpp1', 1, fortran_name='lpp(1)')
4023 self.add_param('lpp2', 1, fortran_name='lpp(2)')
4024 self.add_param('ebeam1', 6500.0, fortran_name='ebeam(1)')
4025 self.add_param('ebeam2', 6500.0, fortran_name='ebeam(2)')
4026 self.add_param('pdlabel', 'nn23nlo', allowed=['lhapdf', 'cteq6_m','cteq6_d','cteq6_l','cteq6l1', 'nn23lo','nn23lo1','nn23nlo'])
4027 self.add_param('lhaid', [244600],fortran_name='lhaPDFid')
4028 self.add_param('lhapdfsetname', ['internal_use_only'], system=True)
4029
4030 self.add_param('parton_shower', 'HERWIG6', fortran_name='shower_mc')
4031 self.add_param('shower_scale_factor',1.0)
4032 self.add_param('fixed_ren_scale', False)
4033 self.add_param('fixed_fac_scale', False)
4034 self.add_param('mur_ref_fixed', 91.118)
4035 self.add_param('muf1_ref_fixed', -1.0, hidden=True)
4036 self.add_param('muf_ref_fixed', 91.118)
4037 self.add_param('muf2_ref_fixed', -1.0, hidden=True)
4038 self.add_param("dynamical_scale_choice", [-1],fortran_name='dyn_scale', comment="\'-1\' is based on CKKW back clustering (following feynman diagram).\n \'1\' is the sum of transverse energy.\n '2' is HT (sum of the transverse mass)\n '3' is HT/2")
4039 self.add_param('fixed_qes_scale', False, hidden=True)
4040 self.add_param('qes_ref_fixed', -1.0, hidden=True)
4041 self.add_param('mur_over_ref', 1.0)
4042 self.add_param('muf_over_ref', 1.0)
4043 self.add_param('muf1_over_ref', -1.0, hidden=True)
4044 self.add_param('muf2_over_ref', -1.0, hidden=True)
4045 self.add_param('qes_over_ref', -1.0, hidden=True)
4046 self.add_param('reweight_scale', [True], fortran_name='lscalevar')
4047 self.add_param('rw_rscale_down', -1.0, hidden=True)
4048 self.add_param('rw_rscale_up', -1.0, hidden=True)
4049 self.add_param('rw_fscale_down', -1.0, hidden=True)
4050 self.add_param('rw_fscale_up', -1.0, hidden=True)
4051 self.add_param('rw_rscale', [1.0,2.0,0.5], fortran_name='scalevarR')
4052 self.add_param('rw_fscale', [1.0,2.0,0.5], fortran_name='scalevarF')
4053 self.add_param('reweight_pdf', [False], fortran_name='lpdfvar')
4054 self.add_param('pdf_set_min', 244601, hidden=True)
4055 self.add_param('pdf_set_max', 244700, hidden=True)
4056 self.add_param('store_rwgt_info', False)
4057 self.add_param('systematics_program', 'none', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics')
4058 self.add_param('systematics_arguments', [''], include=False, hidden=True, comment='Choose the argment to pass to the systematics command. like --mur=0.25,1,4. Look at the help of the systematics function for more details.')
4059
4060
4061 self.add_param('ickkw', 0)
4062 self.add_param('bwcutoff', 15.0)
4063
4064 self.add_param('jetalgo', 1.0)
4065 self.add_param('jetradius', 0.7)
4066 self.add_param('ptj', 10.0 , cut=True)
4067 self.add_param('etaj', -1.0, cut=True)
4068 self.add_param('ptl', 0.0, cut=True)
4069 self.add_param('etal', -1.0, cut=True)
4070 self.add_param('drll', 0.0, cut=True)
4071 self.add_param('drll_sf', 0.0, cut=True)
4072 self.add_param('mll', 0.0, cut=True)
4073 self.add_param('mll_sf', 30.0, cut=True)
4074 self.add_param('ptgmin', 20.0, cut=True)
4075 self.add_param('etagamma', -1.0)
4076 self.add_param('r0gamma', 0.4)
4077 self.add_param('xn', 1.0)
4078 self.add_param('epsgamma', 1.0)
4079 self.add_param('isoem', True)
4080 self.add_param('maxjetflavor', 4, hidden=True)
4081 self.add_param('iappl', 0)
4082 self.add_param('lhe_version', 3, hidden=True, include=False)
4083
4084
4085 self.add_param('FO_LHE_weight_ratio',1e-3, hidden=True, system=True)
4086 self.add_param('FO_LHE_postprocessing',['grouping','random'],
4087 hidden=True, system=True, include=False)
4088
4089
4090 self.add_param('pt_min_pdg',{'__type__':0.}, include=False,cut=True)
4091 self.add_param('pt_max_pdg',{'__type__':0.}, include=False,cut=True)
4092 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False,cut=True)
4093 self.add_param('mxx_only_part_antipart', {'default':False}, include=False, hidden=True)
4094
4095
4096 self.add_param('pdg_cut',[0], hidden=True, system=True)
4097 self.add_param('ptmin4pdg',[0.], hidden=True, system=True)
4098 self.add_param('ptmax4pdg',[-1.], hidden=True, system=True)
4099 self.add_param('mxxmin4pdg',[0.], hidden=True, system=True)
4100 self.add_param('mxxpart_antipart', [False], hidden=True, system=True)
4101
4103 """check the validity of the various input"""
4104
4105 super(RunCardNLO, self).check_validity()
4106
4107
4108 if abs(self['lpp1'])!=1 or abs(self['lpp2'])!=1:
4109 if self['lpp1'] == 1 or self['lpp2']==1:
4110 raise InvalidRunCard('Process like Deep Inelastic scattering not supported at NLO accuracy.')
4111
4112 if self['pdlabel']!='nn23nlo' or self['reweight_pdf']:
4113 self['pdlabel']='nn23nlo'
4114 self['reweight_pdf']=[False]
4115 logger.info('''Lepton-lepton collisions: ignoring PDF related parameters in the run_card.dat (pdlabel, lhaid, reweight_pdf, ...)''')
4116
4117
4118 if self['ickkw'] == 3:
4119
4120 scales=['fixed_ren_scale','fixed_fac_scale','fixed_QES_scale']
4121 for scale in scales:
4122 if self[scale]:
4123 logger.warning('''For consistency in the FxFx merging, \'%s\' has been set to false'''
4124 % scale,'$MG:BOLD')
4125 self[scale]= False
4126
4127 if len(self["dynamical_scale_choice"]) > 1 or self["dynamical_scale_choice"][0] != -1:
4128 self["dynamical_scale_choice"] = [-1]
4129 self["reweight_scale"]=[self["reweight_scale"][0]]
4130 logger.warning('''For consistency in the FxFx merging, dynamical_scale_choice has been set to -1 (default)'''
4131 ,'$MG:BOLD')
4132
4133
4134 jetparams=['jetradius','jetalgo']
4135 for jetparam in jetparams:
4136 if float(self[jetparam]) != 1.0:
4137 logger.info('''For consistency in the FxFx merging, \'%s\' has been set to 1.0'''
4138 % jetparam ,'$MG:BOLD')
4139 self[jetparam] = 1.0
4140 elif self['ickkw'] == -1 and (self["dynamical_scale_choice"][0] != -1 or
4141 len(self["dynamical_scale_choice"]) > 1):
4142 self["dynamical_scale_choice"] = [-1]
4143 self["reweight_scale"]=[self["reweight_scale"][0]]
4144 logger.warning('''For consistency with the jet veto, the scale which will be used is ptj. dynamical_scale_choice will be set at -1.'''
4145 ,'$MG:BOLD')
4146
4147
4148 if self['iappl'] != 0 and self['pdlabel'].lower() != 'lhapdf':
4149 raise InvalidRunCard('APPLgrid generation only possible with the use of LHAPDF')
4150 if self['iappl'] != 0 and not self['reweight_scale']:
4151 raise InvalidRunCard('APPLgrid generation only possible with including' +\
4152 ' the reweighting to get scale dependence')
4153
4154
4155 if self['qes_ref_fixed'] == -1.0:
4156 self['qes_ref_fixed']=self['mur_ref_fixed']
4157 if self['qes_over_ref'] == -1.0:
4158 self['qes_over_ref']=self['mur_over_ref']
4159 if self['muf1_over_ref'] != -1.0 and self['muf1_over_ref'] == self['muf2_over_ref']:
4160 self['muf_over_ref']=self['muf1_over_ref']
4161 if self['muf1_over_ref'] == -1.0:
4162 self['muf1_over_ref']=self['muf_over_ref']
4163 if self['muf2_over_ref'] == -1.0:
4164 self['muf2_over_ref']=self['muf_over_ref']
4165 if self['muf1_ref_fixed'] != -1.0 and self['muf1_ref_fixed'] == self['muf2_ref_fixed']:
4166 self['muf_ref_fixed']=self['muf1_ref_fixed']
4167 if self['muf1_ref_fixed'] == -1.0:
4168 self['muf1_ref_fixed']=self['muf_ref_fixed']
4169 if self['muf2_ref_fixed'] == -1.0:
4170 self['muf2_ref_fixed']=self['muf_ref_fixed']
4171
4172 if (self['rw_rscale_down'] != -1.0 and ['rw_rscale_down'] not in self['rw_rscale']) or\
4173 (self['rw_rscale_up'] != -1.0 and ['rw_rscale_up'] not in self['rw_rscale']):
4174 self['rw_rscale']=[1.0,self['rw_rscale_up'],self['rw_rscale_down']]
4175 if (self['rw_fscale_down'] != -1.0 and ['rw_fscale_down'] not in self['rw_fscale']) or\
4176 (self['rw_fscale_up'] != -1.0 and ['rw_fscale_up'] not in self['rw_fscale']):
4177 self['rw_fscale']=[1.0,self['rw_fscale_up'],self['rw_fscale_down']]
4178
4179
4180 if any(self['reweight_pdf']):
4181
4182 if self['pdlabel'] != "lhapdf":
4183 raise InvalidRunCard('Reweight PDF option requires to use pdf sets associated to lhapdf. Please either change the pdlabel to use LHAPDF or set reweight_pdf to False.')
4184
4185
4186 if self['pdlabel'] != "lhapdf":
4187 self['reweight_pdf']=[self['reweight_pdf'][0]]
4188 self['lhaid']=[self['lhaid'][0]]
4189
4190
4191 if self['fixed_ren_scale'] and self['fixed_fac_scale']:
4192 self['reweight_scale']=[self['reweight_scale'][0]]
4193 self['dynamical_scale_choice']=[0]
4194
4195
4196
4197
4198 if len(self['reweight_pdf']) == 1 and len(self['lhaid']) != 1:
4199 self['reweight_pdf']=self['reweight_pdf']*len(self['lhaid'])
4200 logger.warning("Setting 'reweight_pdf' for all 'lhaid' to %s" % self['reweight_pdf'][0])
4201 if len(self['reweight_scale']) == 1 and len(self['dynamical_scale_choice']) != 1:
4202 self['reweight_scale']=self['reweight_scale']*len(self['dynamical_scale_choice'])
4203 logger.warning("Setting 'reweight_scale' for all 'dynamical_scale_choice' to %s" % self['reweight_pdf'][0])
4204
4205
4206 if len(self['lhaid']) != len(set(self['lhaid'])):
4207 raise InvalidRunCard("'lhaid' has two or more identical entries. They have to be all different for the code to work correctly.")
4208 if len(self['dynamical_scale_choice']) != len(set(self['dynamical_scale_choice'])):
4209 raise InvalidRunCard("'dynamical_scale_choice' has two or more identical entries. They have to be all different for the code to work correctly.")
4210
4211
4212 if len(self['reweight_pdf']) != len(self['lhaid']):
4213 raise InvalidRunCard("'reweight_pdf' and 'lhaid' lists should have the same length")
4214 if len(self['reweight_scale']) != len(self['dynamical_scale_choice']):
4215 raise InvalidRunCard("'reweight_scale' and 'dynamical_scale_choice' lists should have the same length")
4216 if len(self['dynamical_scale_choice']) > 10 :
4217 raise InvalidRunCard("Length of list for 'dynamical_scale_choice' too long: max is 10.")
4218 if len(self['lhaid']) > 25 :
4219 raise InvalidRunCard("Length of list for 'lhaid' too long: max is 25.")
4220 if len(self['rw_rscale']) > 9 :
4221 raise InvalidRunCard("Length of list for 'rw_rscale' too long: max is 9.")
4222 if len(self['rw_fscale']) > 9 :
4223 raise InvalidRunCard("Length of list for 'rw_fscale' too long: max is 9.")
4224
4225 if 1.0 not in self['rw_rscale']:
4226 logger.warning("'1.0' has to be part of 'rw_rscale', adding it")
4227 self['rw_rscale'].insert(0,1.0)
4228 if 1.0 not in self['rw_fscale']:
4229 logger.warning("'1.0' has to be part of 'rw_fscale', adding it")
4230 self['rw_fscale'].insert(0,1.0)
4231 if self['rw_rscale'][0] != 1.0 and 1.0 in self['rw_rscale']:
4232 a=self['rw_rscale'].index(1.0)
4233 self['rw_rscale'][0],self['rw_rscale'][a]=self['rw_rscale'][a],self['rw_rscale'][0]
4234 if self['rw_fscale'][0] != 1.0 and 1.0 in self['rw_fscale']:
4235 a=self['rw_fscale'].index(1.0)
4236 self['rw_fscale'][0],self['rw_fscale'][a]=self['rw_fscale'][a],self['rw_fscale'][0]
4237
4238 if len(self['rw_rscale']) != len(set(self['rw_rscale'])):
4239 raise InvalidRunCard("'rw_rscale' has two or more identical entries. They have to be all different for the code to work correctly.")
4240 if len(self['rw_fscale']) != len(set(self['rw_fscale'])):
4241 raise InvalidRunCard("'rw_fscale' has two or more identical entries. They have to be all different for the code to work correctly.")
4242
4243
4245
4246
4247 pdg_to_cut = set(list(self['pt_min_pdg'].keys()) +list(self['pt_max_pdg'].keys())+
4248 list(self['mxx_min_pdg'].keys())+ list(self['mxx_only_part_antipart'].keys()))
4249 pdg_to_cut.discard('__type__')
4250 pdg_to_cut.discard('default')
4251 if len(pdg_to_cut)>25:
4252 raise Exception("Maximum 25 different PDGs are allowed for PDG specific cut")
4253
4254 if any(int(pdg)<0 for pdg in pdg_to_cut):
4255 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
4256 raise MadGraph5Error('Some PDG specific cuts are defined with negative PDG codes')
4257
4258
4259 if any(pdg in pdg_to_cut for pdg in [21,22,11,13,15]+ list(range(self['maxjetflavor']+1))):
4260
4261 raise Exception("Can not use PDG related cuts for massless SM particles/leptons")
4262 if pdg_to_cut:
4263 self['pdg_cut'] = list(pdg_to_cut)
4264 self['ptmin4pdg'] = []
4265 self['ptmax4pdg'] = []
4266 self['mxxmin4pdg'] = []
4267 self['mxxpart_antipart'] = []
4268 for pdg in self['pdg_cut']:
4269 for var in ['pt','mxx']:
4270 for minmax in ['min', 'max']:
4271 if var == 'mxx' and minmax == 'max':
4272 continue
4273 new_var = '%s%s4pdg' % (var, minmax)
4274 old_var = '%s_%s_pdg' % (var, minmax)
4275 default = 0. if minmax=='min' else -1.
4276 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4277
4278 old_var = 'mxx_only_part_antipart'
4279 new_var = 'mxxpart_antipart'
4280 if 'default' in self[old_var]:
4281 default = self[old_var]['default']
4282 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4283 else:
4284 if str(pdg) not in self[old_var]:
4285 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
4286 self[new_var].append(self[old_var][str(pdg)])
4287 else:
4288 self['pdg_cut'] = [0]
4289 self['ptmin4pdg'] = [0.]
4290 self['ptmax4pdg'] = [-1.]
4291 self['mxxmin4pdg'] = [0.]
4292 self['mxxpart_antipart'] = [False]
4293
4294 - def write(self, output_file, template=None, python_template=False, **opt):
4295 """Write the run_card in output_file according to template
4296 (a path to a valid run_card)"""
4297
4298 if not template:
4299 if not MADEVENT:
4300 template = pjoin(MG5DIR, 'Template', 'NLO', 'Cards',
4301 'run_card.dat')
4302 python_template = True
4303 else:
4304 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
4305 python_template = False
4306
4307 super(RunCardNLO, self).write(output_file, template=template,
4308 python_template=python_template, **opt)
4309
4310
4312 """Rules
4313 e+ e- beam -> lpp:0 ebeam:500
4314 p p beam -> set maxjetflavor automatically
4315 """
4316
4317
4318 beam_id = set()
4319 for proc in proc_def:
4320 for leg in proc['legs']:
4321 if not leg['state']:
4322 beam_id.add(leg['id'])
4323 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
4324 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
4325 self['maxjetflavor'] = maxjetflavor
4326 pass
4327 elif any(id in beam_id for id in [11,-11,13,-13]):
4328 self['lpp1'] = 0
4329 self['lpp2'] = 0
4330 self['ebeam1'] = 500
4331 self['ebeam2'] = 500
4332 else:
4333 self['lpp1'] = 0
4334 self['lpp2'] = 0
4335
4336 if proc_characteristic['ninitial'] == 1:
4337
4338 self.remove_all_cut()
4339
4343 """ a class for storing/dealing with the file MadLoopParam.dat
4344 contains a parser to read it, facilities to write a new file,...
4345 """
4346
4347 _ID_reduction_tool_map = {1:'CutTools',
4348 2:'PJFry++',
4349 3:'IREGI',
4350 4:'Golem95',
4351 5:'Samurai',
4352 6:'Ninja',
4353 7:'COLLIER'}
4354
4356 """initialize the directory to the default value"""
4357
4358 self.add_param("MLReductionLib", "6|7|1")
4359 self.add_param("IREGIMODE", 2)
4360 self.add_param("IREGIRECY", True)
4361 self.add_param("CTModeRun", -1)
4362 self.add_param("MLStabThres", 1e-3)
4363 self.add_param("NRotations_DP", 0)
4364 self.add_param("NRotations_QP", 0)
4365 self.add_param("ImprovePSPoint", 2)
4366 self.add_param("CTLoopLibrary", 2)
4367 self.add_param("CTStabThres", 1e-2)
4368 self.add_param("CTModeInit", 1)
4369 self.add_param("CheckCycle", 3)
4370 self.add_param("MaxAttempts", 10)
4371 self.add_param("ZeroThres", 1e-9)
4372 self.add_param("OSThres", 1.0e-8)
4373 self.add_param("DoubleCheckHelicityFilter", True)
4374 self.add_param("WriteOutFilters", True)
4375 self.add_param("UseLoopFilter", False)
4376 self.add_param("HelicityFilterLevel", 2)
4377 self.add_param("LoopInitStartOver", False)
4378 self.add_param("HelInitStartOver", False)
4379 self.add_param("UseQPIntegrandForNinja", True)
4380 self.add_param("UseQPIntegrandForCutTools", True)
4381 self.add_param("COLLIERMode", 1)
4382 self.add_param("COLLIERComputeUVpoles", True)
4383 self.add_param("COLLIERComputeIRpoles", True)
4384 self.add_param("COLLIERRequiredAccuracy", 1.0e-8)
4385 self.add_param("COLLIERCanOutput",False)
4386 self.add_param("COLLIERGlobalCache",-1)
4387 self.add_param("COLLIERUseCacheForPoles",False)
4388 self.add_param("COLLIERUseInternalStabilityTest",True)
4389
4390 - def read(self, finput):
4391 """Read the input file, this can be a path to a file,
4392 a file object, a str with the content of the file."""
4393
4394 if isinstance(finput, str):
4395 if "\n" in finput:
4396 finput = finput.split('\n')
4397 elif os.path.isfile(finput):
4398 finput = open(finput)
4399 else:
4400 raise Exception("No such file %s" % input)
4401
4402 previous_line= ''
4403 for line in finput:
4404 if previous_line.startswith('#'):
4405 name = previous_line[1:].split()[0]
4406 value = line.strip()
4407 if len(value) and value[0] not in ['#', '!']:
4408 self.__setitem__(name, value, change_userdefine=True)
4409 previous_line = line
4410
4411
4412 - def write(self, outputpath, template=None,commentdefault=False):
4413
4414 if not template:
4415 if not MADEVENT:
4416 template = pjoin(MG5DIR, 'Template', 'loop_material', 'StandAlone',
4417 'Cards', 'MadLoopParams.dat')
4418 else:
4419 template = pjoin(MEDIR, 'Cards', 'MadLoopParams_default.dat')
4420 fsock = open(template, 'r')
4421 template = fsock.readlines()
4422 fsock.close()
4423
4424 if isinstance(outputpath, str):
4425 output = open(outputpath, 'w')
4426 else:
4427 output = outputpath
4428
4429 def f77format(value):
4430 if isinstance(value, bool):
4431 if value:
4432 return '.true.'
4433 else:
4434 return '.false.'
4435 elif isinstance(value, int):
4436 return value
4437 elif isinstance(value, float):
4438 tmp ='%e' % value
4439 return tmp.replace('e','d')
4440 elif isinstance(value, str):
4441 return value
4442 else:
4443 raise Exception("Can not format input %s" % type(value))
4444
4445 name = ''
4446 done = set()
4447 for line in template:
4448 if name:
4449 done.add(name)
4450 if commentdefault and name.lower() not in self.user_set :
4451 output.write('!%s\n' % f77format(self[name]))
4452 else:
4453 output.write('%s\n' % f77format(self[name]))
4454 name=''
4455 continue
4456 elif line.startswith('#'):
4457 name = line[1:].split()[0]
4458 output.write(line)
4459