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