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:]
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 elif 'min' in name:
2718 self[name] = 0
2719 elif 'max' in name:
2720 self[name] = -1
2721 elif 'eta' in name:
2722 self[name] = -1
2723 else:
2724 self[name] = 0
2725
2727 """an object to handle in a nice way the run_card information"""
2728
2729 blocks = [
2730
2731 runblock(name='ion_pdf', fields=('nb_neutron1', 'nb_neutron2','nb_proton1','nb_proton2','mass_ion1', 'mass_ion2'),
2732 template_on=\
2733 """#*********************************************************************
2734 # Heavy ion PDF / rescaling of PDF *
2735 #*********************************************************************
2736 %(nb_proton1)s = nb_proton1 # number of proton for the first beam
2737 %(nb_neutron1)s = nb_neutron1 # number of neutron for the first beam
2738 %(mass_ion1)s = mass_ion1 # mass of the heavy ion (first beam)
2739 # Note that seting differently the two beams only work if you use
2740 # group_subprocess=False when generating your matrix-element
2741 %(nb_proton2)s = nb_proton2 # number of proton for the second beam
2742 %(nb_neutron2)s = nb_neutron2 # number of neutron for the second beam
2743 %(mass_ion2)s = mass_ion2 # mass of the heavy ion (second beam)
2744 """,
2745 template_off='# To see heavy ion options: type "update ion_pdf"'),
2746
2747
2748
2749 runblock(name='beam_pol', fields=('polbeam1','polbeam2'),
2750 template_on=\
2751 """#*********************************************************************
2752 # Beam polarization from -100 (left-handed) to 100 (right-handed) *
2753 #*********************************************************************
2754 %(polbeam1)s = polbeam1 ! beam polarization for beam 1
2755 %(polbeam2)s = polbeam2 ! beam polarization for beam 2
2756 """,
2757 template_off='# To see polarised beam options: type "update beam_pol"'),
2758
2759
2760 runblock(name='syscalc', fields=('sys_scalefact', 'sys_alpsfact','sys_matchscale','sys_pdf'),
2761 template_on=\
2762 """#**************************************
2763 # Parameter below of the systematics study
2764 # will be used by SysCalc (if installed)
2765 #**************************************
2766 #
2767 %(sys_scalefact)s = sys_scalefact # factorization/renormalization scale factor
2768 %(sys_alpsfact)s = sys_alpsfact # \alpha_s emission scale factors
2769 %(sys_matchscale)s = sys_matchscale # variation of merging scale
2770 # PDF sets and number of members (0 or none for all members).
2771 %(sys_pdf)s = sys_pdf # list of pdf sets. (errorset not valid for syscalc)
2772 # MSTW2008nlo68cl.LHgrid 1 = sys_pdf
2773 #
2774 """,
2775 template_off= '# Syscalc is deprecated but to see the associate options type\'update syscalc\''),
2776
2777
2778 runblock(name='ecut', fields=('ej','eb','ea','el','ejmax','ebmax','eamax','elmax','e_min_pdg','e_max_pdg'),
2779 template_on=\
2780 """#*********************************************************************
2781 # Minimum and maximum E's (in the center of mass frame) *
2782 #*********************************************************************
2783 %(ej)s = ej ! minimum E for the jets
2784 %(eb)s = eb ! minimum E for the b
2785 %(ea)s = ea ! minimum E for the photons
2786 %(el)s = el ! minimum E for the charged leptons
2787 %(ejmax)s = ejmax ! maximum E for the jets
2788 %(ebmax)s = ebmax ! maximum E for the b
2789 %(eamax)s = eamax ! maximum E for the photons
2790 %(elmax)s = elmax ! maximum E for the charged leptons
2791 %(e_min_pdg)s = e_min_pdg ! E cut for other particles (use pdg code). Applied on particle and anti-particle
2792 %(e_max_pdg)s = e_max_pdg ! E cut for other particles (syntax e.g. {6: 100, 25: 50})
2793 """,
2794 template_off= '#\n# For display option for energy cut in the partonic center of mass frame type \'update ecut\'\n#'),
2795 ]
2796
2797
2799 """default value for the run_card.dat"""
2800
2801 self.add_param("run_tag", "tag_1", include=False)
2802 self.add_param("gridpack", False)
2803 self.add_param("time_of_flight", -1.0, include=False)
2804 self.add_param("nevents", 10000)
2805 self.add_param("iseed", 0)
2806 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")
2807 self.add_param("lpp1", 1, fortran_name="lpp(1)", allowed=[-1,1,0,2,3,9, -2,-3],
2808 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')
2809 self.add_param("lpp2", 1, fortran_name="lpp(2)", allowed=[-1,1,0,2,3,9],
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("ebeam1", 6500.0, fortran_name="ebeam(1)")
2812 self.add_param("ebeam2", 6500.0, fortran_name="ebeam(2)")
2813 self.add_param("polbeam1", 0.0, fortran_name="pb1", hidden=True,
2814 comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--")
2815 self.add_param("polbeam2", 0.0, fortran_name="pb2", hidden=True,
2816 comment="Beam polarization from -100 (left-handed) to 100 (right-handed) --use lpp=0 for this parameter--")
2817 self.add_param('nb_proton1', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(1)",
2818 comment='For heavy ion physics nb of proton in the ion (for both beam but if group_subprocess was False)')
2819 self.add_param('nb_proton2', 1, hidden=True, allowed=[1,0, 82 , '*'],fortran_name="nb_proton(2)",
2820 comment='For heavy ion physics nb of proton in the ion (used for beam 2 if group_subprocess was False)')
2821 self.add_param('nb_neutron1', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(1)",
2822 comment='For heavy ion physics nb of neutron in the ion (for both beam but if group_subprocess was False)')
2823 self.add_param('nb_neutron2', 0, hidden=True, allowed=[1,0, 126 , '*'],fortran_name="nb_neutron(2)",
2824 comment='For heavy ion physics nb of neutron in the ion (of beam 2 if group_subprocess was False )')
2825 self.add_param('mass_ion1', -1.0, hidden=True, fortran_name="mass_ion(1)",
2826 allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'],
2827 comment='For heavy ion physics mass in GeV of the ion (of beam 1)')
2828 self.add_param('mass_ion2', -1.0, hidden=True, fortran_name="mass_ion(2)",
2829 allowed=[-1,0, 0.938, 207.9766521*0.938, 0.000511, 0.105, '*'],
2830 comment='For heavy ion physics mass in GeV of the ion (of beam 2)')
2831
2832 self.add_param("pdlabel", "nn23lo1", allowed=['lhapdf', 'cteq6_m','cteq6_l', 'cteq6l1','nn23lo', 'nn23lo1', 'nn23nlo']),
2833 self.add_param("lhaid", 230000, hidden=True)
2834 self.add_param("fixed_ren_scale", False)
2835 self.add_param("fixed_fac_scale", False)
2836 self.add_param("scale", 91.1880)
2837 self.add_param("dsqrt_q2fact1", 91.1880, fortran_name="sf1")
2838 self.add_param("dsqrt_q2fact2", 91.1880, fortran_name="sf2")
2839 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",
2840 allowed=[-1,0,1,2,3,4])
2841
2842
2843 self.add_param("bias_module", 'None', include=False)
2844 self.add_param('bias_parameters', {'__type__':1.0}, include='BIAS/bias.inc')
2845
2846
2847 self.add_param("scalefact", 1.0)
2848 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.")
2849 self.add_param("highestmult", 1, fortran_name="nhmult", hidden=True)
2850 self.add_param("ktscheme", 1, hidden=True)
2851 self.add_param("alpsfact", 1.0)
2852 self.add_param("chcluster", False, hidden=True)
2853 self.add_param("pdfwgt", True, hidden=True)
2854 self.add_param("asrwgtflavor", 5, comment = 'highest quark flavor for a_s reweighting in MLM')
2855 self.add_param("clusinfo", True)
2856 self.add_param("lhe_version", 3.0)
2857 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")
2858 self.add_param("event_norm", "average", allowed=['sum','average', 'unity'],
2859 include=False, sys_default='sum')
2860
2861 self.add_param("auto_ptj_mjj", False)
2862 self.add_param("bwcutoff", 15.0)
2863 self.add_param("cut_decays", False)
2864 self.add_param("nhel", 0, include=False)
2865
2866 self.add_param("ptj", 20.0, cut=True)
2867 self.add_param("ptb", 0.0, cut=True)
2868 self.add_param("pta", 10.0, cut=True)
2869 self.add_param("ptl", 10.0, cut=True)
2870 self.add_param("misset", 0.0, cut=True)
2871 self.add_param("ptheavy", 0.0, cut=True, comment='this cut apply on particle heavier than 10 GeV')
2872 self.add_param("ptonium", 1.0, legacy=True)
2873 self.add_param("ptjmax", -1.0, cut=True)
2874 self.add_param("ptbmax", -1.0, cut=True)
2875 self.add_param("ptamax", -1.0, cut=True)
2876 self.add_param("ptlmax", -1.0, cut=True)
2877 self.add_param("missetmax", -1.0, cut=True)
2878
2879 self.add_param("ej", 0.0, cut=True, hidden=True)
2880 self.add_param("eb", 0.0, cut=True, hidden=True)
2881 self.add_param("ea", 0.0, cut=True, hidden=True)
2882 self.add_param("el", 0.0, cut=True, hidden=True)
2883 self.add_param("ejmax", -1.0, cut=True, hidden=True)
2884 self.add_param("ebmax", -1.0, cut=True, hidden=True)
2885 self.add_param("eamax", -1.0, cut=True, hidden=True)
2886 self.add_param("elmax", -1.0, cut=True, hidden=True)
2887
2888 self.add_param("etaj", 5.0, cut=True)
2889 self.add_param("etab", -1.0, cut=True)
2890 self.add_param("etaa", 2.5, cut=True)
2891 self.add_param("etal", 2.5, cut=True)
2892 self.add_param("etaonium", 0.6, legacy=True)
2893 self.add_param("etajmin", 0.0, cut=True)
2894 self.add_param("etabmin", 0.0, cut=True)
2895 self.add_param("etaamin", 0.0, cut=True)
2896 self.add_param("etalmin", 0.0, cut=True)
2897
2898 self.add_param("drjj", 0.4, cut=True)
2899 self.add_param("drbb", 0.0, cut=True)
2900 self.add_param("drll", 0.4, cut=True)
2901 self.add_param("draa", 0.4, cut=True)
2902 self.add_param("drbj", 0.0, cut=True)
2903 self.add_param("draj", 0.4, cut=True)
2904 self.add_param("drjl", 0.4, cut=True)
2905 self.add_param("drab", 0.0, cut=True)
2906 self.add_param("drbl", 0.0, cut=True)
2907 self.add_param("dral", 0.4, cut=True)
2908 self.add_param("drjjmax", -1.0, cut=True)
2909 self.add_param("drbbmax", -1.0, cut=True)
2910 self.add_param("drllmax", -1.0, cut=True)
2911 self.add_param("draamax", -1.0, cut=True)
2912 self.add_param("drbjmax", -1.0, cut=True)
2913 self.add_param("drajmax", -1.0, cut=True)
2914 self.add_param("drjlmax", -1.0, cut=True)
2915 self.add_param("drabmax", -1.0, cut=True)
2916 self.add_param("drblmax", -1.0, cut=True)
2917 self.add_param("dralmax", -1.0, cut=True)
2918
2919 self.add_param("mmjj", 0.0, cut=True)
2920 self.add_param("mmbb", 0.0, cut=True)
2921 self.add_param("mmaa", 0.0, cut=True)
2922 self.add_param("mmll", 0.0, cut=True)
2923 self.add_param("mmjjmax", -1.0, cut=True)
2924 self.add_param("mmbbmax", -1.0, cut=True)
2925 self.add_param("mmaamax", -1.0, cut=True)
2926 self.add_param("mmllmax", -1.0, cut=True)
2927 self.add_param("mmnl", 0.0, cut=True)
2928 self.add_param("mmnlmax", -1.0, cut=True)
2929
2930 self.add_param("ptllmin", 0.0, cut=True)
2931 self.add_param("ptllmax", -1.0, cut=True)
2932 self.add_param("xptj", 0.0, cut=True)
2933 self.add_param("xptb", 0.0, cut=True)
2934 self.add_param("xpta", 0.0, cut=True)
2935 self.add_param("xptl", 0.0, cut=True)
2936
2937 self.add_param("ptj1min", 0.0, cut=True)
2938 self.add_param("ptj1max", -1.0, cut=True)
2939 self.add_param("ptj2min", 0.0, cut=True)
2940 self.add_param("ptj2max", -1.0, cut=True)
2941 self.add_param("ptj3min", 0.0, cut=True)
2942 self.add_param("ptj3max", -1.0, cut=True)
2943 self.add_param("ptj4min", 0.0, cut=True)
2944 self.add_param("ptj4max", -1.0, cut=True)
2945 self.add_param("cutuse", 0, cut=True)
2946
2947 self.add_param("ptl1min", 0.0, cut=True)
2948 self.add_param("ptl1max", -1.0, cut=True)
2949 self.add_param("ptl2min", 0.0, cut=True)
2950 self.add_param("ptl2max", -1.0, cut=True)
2951 self.add_param("ptl3min", 0.0, cut=True)
2952 self.add_param("ptl3max", -1.0, cut=True)
2953 self.add_param("ptl4min", 0.0, cut=True)
2954 self.add_param("ptl4max", -1.0, cut=True)
2955
2956 self.add_param("htjmin", 0.0, cut=True)
2957 self.add_param("htjmax", -1.0, cut=True)
2958 self.add_param("ihtmin", 0.0, cut=True)
2959 self.add_param("ihtmax", -1.0, cut=True)
2960 self.add_param("ht2min", 0.0, cut=True)
2961 self.add_param("ht3min", 0.0, cut=True)
2962 self.add_param("ht4min", 0.0, cut=True)
2963 self.add_param("ht2max", -1.0, cut=True)
2964 self.add_param("ht3max", -1.0, cut=True)
2965 self.add_param("ht4max", -1.0, cut=True)
2966
2967 self.add_param("ptgmin", 0.0, cut=True)
2968 self.add_param("r0gamma", 0.4)
2969 self.add_param("xn", 1.0)
2970 self.add_param("epsgamma", 1.0)
2971 self.add_param("isoem", True)
2972 self.add_param("xetamin", 0.0, cut=True)
2973 self.add_param("deltaeta", 0.0, cut=True)
2974 self.add_param("ktdurham", -1.0, fortran_name="kt_durham", cut=True)
2975 self.add_param("dparameter", 0.4, fortran_name="d_parameter", cut=True)
2976 self.add_param("ptlund", -1.0, fortran_name="pt_lund", cut=True)
2977 self.add_param("pdgs_for_merging_cut", [21, 1, 2, 3, 4, 5, 6])
2978 self.add_param("maxjetflavor", 4)
2979 self.add_param("xqcut", 0.0, cut=True)
2980 self.add_param("use_syst", True)
2981 self.add_param('systematics_program', 'systematics', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics, syscalc')
2982 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.')
2983
2984 self.add_param("sys_scalefact", "0.5 1 2", include=False, hidden=True)
2985 self.add_param("sys_alpsfact", "None", include=False, hidden=True)
2986 self.add_param("sys_matchscale", "auto", include=False, hidden=True)
2987 self.add_param("sys_pdf", "errorset", include=False, hidden=True)
2988 self.add_param("sys_scalecorrelation", -1, include=False, hidden=True)
2989
2990
2991 self.add_param('gridrun', False, hidden=True)
2992 self.add_param('fixed_couplings', True, hidden=True)
2993 self.add_param('mc_grouped_subproc', True, hidden=True)
2994 self.add_param('xmtcentral', 0.0, hidden=True, fortran_name="xmtc")
2995 self.add_param('d', 1.0, hidden=True)
2996 self.add_param('gseed', 0, hidden=True, include=False)
2997 self.add_param('issgridfile', '', hidden=True)
2998
2999 self.add_param('job_strategy', 0, hidden=True, include=False, allowed=[0,1,2], comment='see appendix of 1507.00020 (page 26)')
3000 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.")
3001 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")
3002 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)")
3003 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")
3004
3005
3006
3007 self.add_param('pt_min_pdg',{'__type__':0.}, include=False)
3008 self.add_param('pt_max_pdg',{'__type__':0.}, include=False)
3009 self.add_param('E_min_pdg',{'__type__':0.}, include=False, hidden=True)
3010 self.add_param('E_max_pdg',{'__type__':0.}, include=False, hidden=True)
3011 self.add_param('eta_min_pdg',{'__type__':0.}, include=False)
3012 self.add_param('eta_max_pdg',{'__type__':0.}, include=False)
3013 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False)
3014 self.add_param('mxx_only_part_antipart', {'default':False}, include=False)
3015
3016 self.add_param('pdg_cut',[0], system=True)
3017 self.add_param('ptmin4pdg',[0.], system=True)
3018 self.add_param('ptmax4pdg',[-1.], system=True)
3019 self.add_param('Emin4pdg',[0.], system=True)
3020 self.add_param('Emax4pdg',[-1.], system=True)
3021 self.add_param('etamin4pdg',[0.], system=True)
3022 self.add_param('etamax4pdg',[-1.], system=True)
3023 self.add_param('mxxmin4pdg',[-1.], system=True)
3024 self.add_param('mxxpart_antipart', [False], system=True)
3025
3026
3027
3029 """ """
3030
3031 super(RunCardLO, self).check_validity()
3032
3033
3034
3035
3036 if 'nhel' not in self.user_set:
3037 raise InvalidRunCard, "Parameter nhel is not defined in the run_card."
3038 if self['nhel'] not in [1,0]:
3039 raise InvalidRunCard, "Parameter nhel can only be '0' or '1', "+\
3040 "not %s." % self['nhel']
3041 if int(self['maxjetflavor']) > 6:
3042 raise InvalidRunCard, 'maxjetflavor should be lower than 5! (6 is partly supported)'
3043
3044 if len(self['pdgs_for_merging_cut']) > 1000:
3045 raise InvalidRunCard, "The number of elements in "+\
3046 "'pdgs_for_merging_cut' should not exceed 1000."
3047
3048
3049 if self['ptgmin'] > 0:
3050 if self['pta'] > 0:
3051 logger.warning('pta cut discarded since photon isolation is used')
3052 self['pta'] = 0.0
3053 if self['draj'] > 0:
3054 logger.warning('draj cut discarded since photon isolation is used')
3055 self['draj'] = 0.0
3056
3057
3058 if self['gridrun']:
3059 self['iseed'] = self['gseed']
3060
3061
3062 if self['use_syst']:
3063 if self['scalefact'] != 1.0:
3064 logger.warning('Since use_syst=T, We change the value of \'scalefact\' to 1')
3065 self['scalefact'] = 1.0
3066
3067
3068 if self['ickkw'] > 0:
3069 if self['ickkw'] != 1:
3070 logger.critical('ickkw >1 is pure alpha and only partly implemented.')
3071 import madgraph.interface.extended_cmd as basic_cmd
3072 answer = basic_cmd.smart_input('Do you really want to continue', allow_arg=['y','n'], default='n')
3073 if answer !='y':
3074 raise InvalidRunCard, 'ickkw>1 is still in alpha'
3075 if self['use_syst']:
3076
3077 if self['alpsfact'] != 1.0:
3078 logger.warning('Since use_syst=T, We change the value of \'alpsfact\' to 1')
3079 self['alpsfact'] =1.0
3080 if self['maxjetflavor'] == 6:
3081 raise InvalidRunCard, 'maxjetflavor at 6 is NOT supported for matching!'
3082 if self['ickkw'] == 2:
3083
3084 self.get_default('highestmult', log_level=20)
3085 self.get_default('issgridfile', 'issudgrid.dat', log_level=20)
3086 if self['xqcut'] > 0:
3087 if self['ickkw'] == 0:
3088 logger.error('xqcut>0 but ickkw=0. Potentially not fully consistent setup. Be carefull')
3089 import time
3090 time.sleep(5)
3091 if self['drjj'] != 0:
3092 logger.warning('Since icckw>0, We change the value of \'drjj\' to 0')
3093 self['drjj'] = 0
3094 if self['drjl'] != 0:
3095 logger.warning('Since icckw>0, We change the value of \'drjl\' to 0')
3096 self['drjl'] = 0
3097 if not self['auto_ptj_mjj']:
3098 if self['mmjj'] > self['xqcut']:
3099 logger.warning('mmjj > xqcut (and auto_ptj_mjj = F). MMJJ set to 0')
3100 self['mmjj'] = 0.0
3101
3102
3103
3104
3105 if self['pdlabel'] == 'lhapdf':
3106
3107 self.get_default('lhaid', log_level=20)
3108
3110
3111
3112 pdg_to_cut = set(self['pt_min_pdg'].keys() +self['pt_max_pdg'].keys() +
3113 self['e_min_pdg'].keys() +self['e_max_pdg'].keys() +
3114 self['eta_min_pdg'].keys() +self['eta_max_pdg'].keys()+
3115 self['mxx_min_pdg'].keys() + self['mxx_only_part_antipart'].keys())
3116 pdg_to_cut.discard('__type__')
3117 pdg_to_cut.discard('default')
3118 if len(pdg_to_cut)>25:
3119 raise Exception, "Maximum 25 different pdgs are allowed for pdg specific cut"
3120
3121 if any(int(pdg)<0 for pdg in pdg_to_cut):
3122 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
3123 raise MadGraph5Error, 'Some PDG specific cuts are defined with negative pdg code'
3124
3125
3126 if any(pdg in pdg_to_cut for pdg in [1,2,3,4,5,21,22,11,13,15]):
3127 raise Exception, "Can not use PDG related cut for light quark/b quark/lepton/gluon/photon"
3128
3129 if pdg_to_cut:
3130 self['pdg_cut'] = list(pdg_to_cut)
3131 self['ptmin4pdg'] = []
3132 self['Emin4pdg'] = []
3133 self['etamin4pdg'] =[]
3134 self['ptmax4pdg'] = []
3135 self['Emax4pdg'] = []
3136 self['etamax4pdg'] =[]
3137 self['mxxmin4pdg'] =[]
3138 self['mxxpart_antipart'] = []
3139 for pdg in self['pdg_cut']:
3140 for var in ['pt','e','eta', 'Mxx']:
3141 for minmax in ['min', 'max']:
3142 if var in ['Mxx'] and minmax =='max':
3143 continue
3144 new_var = '%s%s4pdg' % (var, minmax)
3145 old_var = '%s_%s_pdg' % (var, minmax)
3146 default = 0. if minmax=='min' else -1.
3147 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3148
3149 old_var = 'mxx_only_part_antipart'
3150 new_var = 'mxxpart_antipart'
3151 if 'default' in self[old_var]:
3152 default = self[old_var]['default']
3153 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
3154 else:
3155 if str(pdg) not in self[old_var]:
3156 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
3157 self[new_var].append(self[old_var][str(pdg)])
3158 else:
3159 self['pdg_cut'] = [0]
3160 self['ptmin4pdg'] = [0.]
3161 self['Emin4pdg'] = [0.]
3162 self['etamin4pdg'] =[0.]
3163 self['ptmax4pdg'] = [-1.]
3164 self['Emax4pdg'] = [-1.]
3165 self['etamax4pdg'] =[-1.]
3166 self['mxxmin4pdg'] =[0.]
3167 self['mxxpart_antipart'] = [False]
3168
3169
3170
3172 """Rules
3173 process 1->N all cut set on off.
3174 loop_induced -> MC over helicity
3175 e+ e- beam -> lpp:0 ebeam:500
3176 p p beam -> set maxjetflavor automatically
3177 more than one multiplicity: ickkw=1 xqcut=30 use_syst=F
3178 """
3179
3180 if proc_characteristic['loop_induced']:
3181 self['nhel'] = 1
3182 self['pdgs_for_merging_cut'] = proc_characteristic['colored_pdgs']
3183
3184 if proc_characteristic['ninitial'] == 1:
3185
3186 self.remove_all_cut()
3187 self['use_syst'] = False
3188 else:
3189
3190 beam_id = set()
3191 for proc in proc_def:
3192 for oneproc in proc:
3193 for leg in oneproc['legs']:
3194 if not leg['state']:
3195 beam_id.add(leg['id'])
3196 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
3197 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
3198 self['maxjetflavor'] = maxjetflavor
3199 self['asrwgtflavor'] = maxjetflavor
3200 pass
3201 elif 11 in beam_id or -11 in beam_id:
3202 self['lpp1'] = 0
3203 self['lpp2'] = 0
3204 self['ebeam1'] = 500
3205 self['ebeam2'] = 500
3206 self['use_syst'] = False
3207 self.display_block.append('beam_pol')
3208 self.display_block.append('ecut')
3209 else:
3210 self['lpp1'] = 0
3211 self['lpp2'] = 0
3212 self['use_syst'] = False
3213 self.display_block.append('beam_pol')
3214
3215
3216 min_particle = 99
3217 max_particle = 0
3218 for proc in proc_def:
3219 min_particle = min(len(proc[0]['legs']), min_particle)
3220 max_particle = max(len(proc[0]['legs']), max_particle)
3221 if min_particle != max_particle:
3222
3223 for procmin in proc_def:
3224 if len(procmin[0]['legs']) != min_particle:
3225 continue
3226 else:
3227 idsmin = [l['id'] for l in procmin[0]['legs']]
3228 break
3229 matching = False
3230 for procmax in proc_def:
3231 if len(procmax[0]['legs']) != max_particle:
3232 continue
3233 idsmax = [l['id'] for l in procmax[0]['legs']]
3234 for i in idsmin:
3235 if i not in idsmax:
3236 continue
3237 else:
3238 idsmax.remove(i)
3239 for j in idsmax:
3240 if j not in [1,-1,2,-2,3,-3,4,-4,5,-5,21]:
3241 break
3242 else:
3243
3244 matching=True
3245 break
3246
3247 if matching:
3248 self['ickkw'] = 1
3249 self['xqcut'] = 30
3250
3251 self['drjj'] = 0
3252 self['drjl'] = 0
3253 self['sys_alpsfact'] = "0.5 1 2"
3254
3255
3256
3257 no_systematics = False
3258 for proc in proc_def:
3259 for oneproc in proc:
3260 if '^2' in oneproc.nice_string():
3261 no_systematics = True
3262 break
3263 else:
3264 continue
3265 break
3266
3267
3268 if no_systematics:
3269 self['use_syst'] = False
3270 self['systematics_program'] = 'none'
3271
3272 if 'MLM' in proc_characteristic['limitations']:
3273 if self['dynamical_scale_choice'] == -1:
3274 self['dynamical_scale_choice'] = 3
3275 if self['ickkw'] == 1:
3276 logger.critical("MLM matching/merging not compatible with the model! You need to use another method to remove the double counting!")
3277 self['ickkw'] = 0
3278
3279
3280 - def write(self, output_file, template=None, python_template=False,
3281 **opt):
3282 """Write the run_card in output_file according to template
3283 (a path to a valid run_card)"""
3284
3285 if not template:
3286 if not MADEVENT:
3287 template = pjoin(MG5DIR, 'Template', 'LO', 'Cards',
3288 'run_card.dat')
3289 python_template = True
3290 else:
3291 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
3292 python_template = False
3293
3294 super(RunCardLO, self).write(output_file, template=template,
3295 python_template=python_template, **opt)
3296
3300
3302 """ A class to store a MadAnalysis5 card. Very basic since it is basically
3303 free format."""
3304
3305 _MG5aMC_escape_tag = '@MG5aMC'
3306
3307 _default_hadron_inputs = ['*.hepmc', '*.hep', '*.stdhep', '*.lhco','*.root']
3308 _default_parton_inputs = ['*.lhe']
3309 _skip_analysis = False
3310
3311 @classmethod
3313 """ Checks from the type of an event file whether it can be reconstructed or not."""
3314 return not (file_path.endswith('.lhco') or file_path.endswith('.lhco.gz') or \
3315 file_path.endswith('.root') or file_path.endswith('.root.gz'))
3316
3317 @classmethod
3319 """ A method returning the structure of an empty analysis """
3320 return {'commands':[],
3321 'reconstructions':[]}
3322
3323 @classmethod
3325 """ A method returning the structure of an empty reconstruction """
3326 return {'commands':[],
3327 'reco_output':'lhe'}
3328
3330 """define the default value"""
3331 self['mode'] = 'parton'
3332 self['inputs'] = []
3333
3334 self['stdout_lvl'] = None
3335
3336
3337
3338
3339
3340
3341
3342 self['analyses'] = {}
3343
3344
3345 self['recasting'] = {'commands':[],'card':[]}
3346
3347
3348 self['reconstruction'] = {'lhco_input':
3349 MadAnalysis5Card.empty_reconstruction(),
3350 'root_input':
3351 MadAnalysis5Card.empty_reconstruction()}
3352 self['reconstruction']['lhco_input']['reco_output']='lhco'
3353 self['reconstruction']['root_input']['reco_output']='root'
3354
3355
3356 self['order'] = []
3357
3358 - def __init__(self, finput=None,mode=None):
3359 if isinstance(finput, self.__class__):
3360 dict.__init__(self, finput)
3361 assert finput.__dict__.keys()
3362 for key in finput.__dict__:
3363 setattr(self, key, copy.copy(getattr(finput, key)) )
3364 return
3365 else:
3366 dict.__init__(self)
3367
3368
3369 self.default_setup()
3370 if not mode is None:
3371 self['mode']=mode
3372
3373
3374 if isinstance(finput, (file, str, StringIO.StringIO)):
3375 self.read(finput, mode=mode)
3376
3377 - def read(self, input, mode=None):
3378 """ Read an MA5 card"""
3379
3380 if mode not in [None,'parton','hadron']:
3381 raise MadGraph5Error('A MadAnalysis5Card can be read online the modes'+
3382 "'parton' or 'hadron'")
3383 card_mode = mode
3384
3385 if isinstance(input, (file, StringIO.StringIO)):
3386 input_stream = input
3387 elif isinstance(input, str):
3388 if not os.path.isfile(input):
3389 raise InvalidMadAnalysis5Card("Cannot read the MadAnalysis5 card."+\
3390 "File '%s' not found."%input)
3391 if mode is None and 'hadron' in input:
3392 card_mode = 'hadron'
3393 input_stream = open(input,'r')
3394 else:
3395 raise MadGraph5Error('Incorrect input for the read function of'+\
3396 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(input)))
3397
3398
3399 self.__init__()
3400 current_name = 'default'
3401 current_type = 'analyses'
3402 for line in input_stream:
3403
3404 if line.startswith('#'):
3405 continue
3406 if line.endswith('\n'):
3407 line = line[:-1]
3408 if line.strip()=='':
3409 continue
3410 if line.startswith(self._MG5aMC_escape_tag):
3411 try:
3412 option,value = line[len(self._MG5aMC_escape_tag):].split('=')
3413 value = value.strip()
3414 except ValueError:
3415 option = line[len(self._MG5aMC_escape_tag):]
3416 option = option.strip()
3417
3418 if option=='inputs':
3419 self['inputs'].extend([v.strip() for v in value.split(',')])
3420
3421 elif option == 'skip_analysis':
3422 self._skip_analysis = True
3423
3424 elif option=='stdout_lvl':
3425 try:
3426 self['stdout_lvl']=int(value)
3427 except ValueError:
3428 try:
3429 self['stdout_lvl']=eval(value)
3430 except:
3431 try:
3432 self['stdout_lvl']=eval('logging.%s'%value)
3433 except:
3434 raise InvalidMadAnalysis5Card(
3435 "MA5 output level specification '%s' is incorrect."%str(value))
3436
3437 elif option=='analysis_name':
3438 current_type = 'analyses'
3439 current_name = value
3440 if current_name in self[current_type]:
3441 raise InvalidMadAnalysis5Card(
3442 "Analysis '%s' already defined in MadAnalysis5 card"%current_name)
3443 else:
3444 self[current_type][current_name] = MadAnalysis5Card.empty_analysis()
3445
3446 elif option=='set_reconstructions':
3447 try:
3448 reconstructions = eval(value)
3449 if not isinstance(reconstructions, list):
3450 raise
3451 except:
3452 raise InvalidMadAnalysis5Card("List of reconstructions"+\
3453 " '%s' could not be parsed in MadAnalysis5 card."%value)
3454 if current_type!='analyses' and current_name not in self[current_type]:
3455 raise InvalidMadAnalysis5Card("A list of reconstructions"+\
3456 "can only be defined in the context of an "+\
3457 "analysis in a MadAnalysis5 card.")
3458 self[current_type][current_name]['reconstructions']=reconstructions
3459 continue
3460
3461 elif option=='reconstruction_name':
3462 current_type = 'reconstruction'
3463 current_name = value
3464 if current_name in self[current_type]:
3465 raise InvalidMadAnalysis5Card(
3466 "Reconstruction '%s' already defined in MadAnalysis5 hadron card"%current_name)
3467 else:
3468 self[current_type][current_name] = MadAnalysis5Card.empty_reconstruction()
3469
3470 elif option=='reco_output':
3471 if current_type!='reconstruction' or current_name not in \
3472 self['reconstruction']:
3473 raise InvalidMadAnalysis5Card(
3474 "Option '%s' is only available within the definition of a reconstruction"%option)
3475 if not value.lower() in ['lhe','root']:
3476 raise InvalidMadAnalysis5Card(
3477 "Option '%s' can only take the values 'lhe' or 'root'"%option)
3478 self['reconstruction'][current_name]['reco_output'] = value.lower()
3479
3480 elif option.startswith('recasting'):
3481 current_type = 'recasting'
3482 try:
3483 current_name = option.split('_')[1]
3484 except:
3485 raise InvalidMadAnalysis5Card('Malformed MA5 recasting option %s.'%option)
3486 if len(self['recasting'][current_name])>0:
3487 raise InvalidMadAnalysis5Card(
3488 "Only one recasting can be defined in MadAnalysis5 hadron card")
3489
3490 else:
3491 raise InvalidMadAnalysis5Card(
3492 "Unreckognized MG5aMC instruction in MadAnalysis5 card: '%s'"%option)
3493
3494 if option in ['analysis_name','reconstruction_name'] or \
3495 option.startswith('recasting'):
3496 self['order'].append((current_type,current_name))
3497 continue
3498
3499
3500
3501 if current_name == 'default' and current_type == 'analyses' and\
3502 'default' not in self['analyses']:
3503 self['analyses']['default'] = MadAnalysis5Card.empty_analysis()
3504 self['order'].append(('analyses','default'))
3505
3506 if current_type in ['recasting']:
3507 self[current_type][current_name].append(line)
3508 elif current_type in ['reconstruction']:
3509 self[current_type][current_name]['commands'].append(line)
3510 elif current_type in ['analyses']:
3511 self[current_type][current_name]['commands'].append(line)
3512
3513 if 'reconstruction' in self['analyses'] or len(self['recasting']['card'])>0:
3514 if mode=='parton':
3515 raise InvalidMadAnalysis5Card(
3516 "A parton MadAnalysis5 card cannot specify a recombination or recasting.")
3517 card_mode = 'hadron'
3518 elif mode is None:
3519 card_mode = 'parton'
3520
3521 self['mode'] = card_mode
3522 if self['inputs'] == []:
3523 if self['mode']=='hadron':
3524 self['inputs'] = self._default_hadron_inputs
3525 else:
3526 self['inputs'] = self._default_parton_inputs
3527
3528
3529
3530 if self['mode']=='hadron':
3531 for analysis_name, analysis in self['analyses'].items():
3532 if len(analysis['reconstructions'])==0:
3533 raise InvalidMadAnalysis5Card('Hadron-level analysis '+\
3534 "'%s' is not specified any reconstruction(s)."%analysis_name)
3535 if any(reco not in self['reconstruction'] for reco in \
3536 analysis['reconstructions']):
3537 raise InvalidMadAnalysis5Card('A reconstructions specified in'+\
3538 " analysis '%s' is not defined."%analysis_name)
3539
3540 - def write(self, output):
3541 """ Write an MA5 card."""
3542
3543 if isinstance(output, (file, StringIO.StringIO)):
3544 output_stream = output
3545 elif isinstance(output, str):
3546 output_stream = open(output,'w')
3547 else:
3548 raise MadGraph5Error('Incorrect input for the write function of'+\
3549 ' the MadAnalysis5Card card. Received argument type is: %s'%str(type(output)))
3550
3551 output_lines = []
3552 if self._skip_analysis:
3553 output_lines.append('%s skip_analysis'%self._MG5aMC_escape_tag)
3554 output_lines.append('%s inputs = %s'%(self._MG5aMC_escape_tag,','.join(self['inputs'])))
3555 if not self['stdout_lvl'] is None:
3556 output_lines.append('%s stdout_lvl=%s'%(self._MG5aMC_escape_tag,self['stdout_lvl']))
3557 for definition_type, name in self['order']:
3558
3559 if definition_type=='analyses':
3560 output_lines.append('%s analysis_name = %s'%(self._MG5aMC_escape_tag,name))
3561 output_lines.append('%s set_reconstructions = %s'%(self._MG5aMC_escape_tag,
3562 str(self['analyses'][name]['reconstructions'])))
3563 elif definition_type=='reconstruction':
3564 output_lines.append('%s reconstruction_name = %s'%(self._MG5aMC_escape_tag,name))
3565 elif definition_type=='recasting':
3566 output_lines.append('%s recasting_%s'%(self._MG5aMC_escape_tag,name))
3567
3568 if definition_type in ['recasting']:
3569 output_lines.extend(self[definition_type][name])
3570 elif definition_type in ['reconstruction']:
3571 output_lines.append('%s reco_output = %s'%(self._MG5aMC_escape_tag,
3572 self[definition_type][name]['reco_output']))
3573 output_lines.extend(self[definition_type][name]['commands'])
3574 elif definition_type in ['analyses']:
3575 output_lines.extend(self[definition_type][name]['commands'])
3576
3577 output_stream.write('\n'.join(output_lines))
3578
3579 return
3580
3581 - def get_MA5_cmds(self, inputs_arg, submit_folder, run_dir_path=None,
3582 UFO_model_path=None, run_tag=''):
3583 """ Returns a list of tuples ('AnalysisTag',['commands']) specifying
3584 the commands of the MadAnalysis runs required from this card.
3585 At parton-level, the number of such commands is the number of analysis
3586 asked for. In the future, the idea is that the entire card can be
3587 processed in one go from MA5 directly."""
3588
3589 if isinstance(inputs_arg, list):
3590 inputs = inputs_arg
3591 elif isinstance(inputs_arg, str):
3592 inputs = [inputs_arg]
3593 else:
3594 raise MadGraph5Error("The function 'get_MA5_cmds' can only take "+\
3595 " a string or a list for the argument 'inputs_arg'")
3596
3597 if len(inputs)==0:
3598 raise MadGraph5Error("The function 'get_MA5_cmds' must have "+\
3599 " at least one input specified'")
3600
3601 if run_dir_path is None:
3602 run_dir_path = os.path.dirname(inputs_arg)
3603
3604 cmds_list = []
3605
3606 UFO_load = []
3607
3608 if UFO_model_path:
3609 UFO_load.append('import %s'%UFO_model_path)
3610
3611 def get_import(input, type=None):
3612 """ Generates the MA5 import commands for that event file. """
3613 dataset_name = os.path.basename(input).split('.')[0]
3614 res = ['import %s as %s'%(input, dataset_name)]
3615 if not type is None:
3616 res.append('set %s.type = %s'%(dataset_name, type))
3617 return res
3618
3619 fifo_status = {'warned_fifo':False,'fifo_used_up':False}
3620 def warn_fifo(input):
3621 if not input.endswith('.fifo'):
3622 return False
3623 if not fifo_status['fifo_used_up']:
3624 fifo_status['fifo_used_up'] = True
3625 return False
3626 else:
3627 if not fifo_status['warned_fifo']:
3628 logger.warning('Only the first MA5 analysis/reconstructions can be run on a fifo. Subsequent runs will skip fifo inputs.')
3629 fifo_status['warned_fifo'] = True
3630 return True
3631
3632
3633 inputs_load = []
3634 for input in inputs:
3635 inputs_load.extend(get_import(input))
3636
3637 submit_command = 'submit %s'%submit_folder+'_%s'
3638
3639
3640
3641
3642 reconstruction_outputs = {
3643 'lhco_input':[f for f in inputs if
3644 f.endswith('.lhco') or f.endswith('.lhco.gz')],
3645 'root_input':[f for f in inputs if
3646 f.endswith('.root') or f.endswith('.root.gz')]}
3647
3648
3649 recasting_card_path = pjoin(run_dir_path,
3650 '_'.join([run_tag,os.path.basename(submit_folder),'recasting_card.dat']))
3651
3652
3653 for definition_type, name in self['order']:
3654 if definition_type == 'reconstruction':
3655 analysis_cmds = list(self['reconstruction'][name]['commands'])
3656 reco_outputs = []
3657 for i_input, input in enumerate(inputs):
3658
3659 if not MadAnalysis5Card.events_can_be_reconstructed(input):
3660 continue
3661
3662 if warn_fifo(input):
3663 continue
3664 analysis_cmds.append('import %s as reco_events'%input)
3665 if self['reconstruction'][name]['reco_output']=='lhe':
3666 reco_outputs.append('%s_%s.lhe.gz'%(os.path.basename(
3667 input).replace('_events','').split('.')[0],name))
3668 analysis_cmds.append('set main.outputfile=%s'%reco_outputs[-1])
3669 elif self['reconstruction'][name]['reco_output']=='root':
3670 reco_outputs.append('%s_%s.root'%(os.path.basename(
3671 input).replace('_events','').split('.')[0],name))
3672 analysis_cmds.append('set main.fastsim.rootfile=%s'%reco_outputs[-1])
3673 analysis_cmds.append(
3674 submit_command%('reco_%s_%d'%(name,i_input+1)))
3675 analysis_cmds.append('remove reco_events')
3676
3677 reconstruction_outputs[name]= [pjoin(run_dir_path,rec_out)
3678 for rec_out in reco_outputs]
3679 if len(reco_outputs)>0:
3680 cmds_list.append(('_reco_%s'%name,analysis_cmds))
3681
3682 elif definition_type == 'analyses':
3683 if self['mode']=='parton':
3684 cmds_list.append( (name, UFO_load+inputs_load+
3685 self['analyses'][name]['commands']+[submit_command%name]) )
3686 elif self['mode']=='hadron':
3687
3688 for reco in self['analyses'][name]['reconstructions']+\
3689 ['lhco_input','root_input']:
3690 if len(reconstruction_outputs[reco])==0:
3691 continue
3692 if self['reconstruction'][reco]['reco_output']=='lhe':
3693
3694 analysis_cmds = ['set main.mode = parton']
3695 else:
3696 analysis_cmds = []
3697 analysis_cmds.extend(sum([get_import(rec_out) for
3698 rec_out in reconstruction_outputs[reco]],[]))
3699 analysis_cmds.extend(self['analyses'][name]['commands'])
3700 analysis_cmds.append(submit_command%('%s_%s'%(name,reco)))
3701 cmds_list.append( ('%s_%s'%(name,reco),analysis_cmds) )
3702
3703 elif definition_type == 'recasting':
3704 if len(self['recasting']['card'])==0:
3705 continue
3706 if name == 'card':
3707
3708 open(recasting_card_path,'w').write('\n'.join(self['recasting']['card']))
3709 if name == 'commands':
3710 recasting_cmds = list(self['recasting']['commands'])
3711
3712 n_inputs = 0
3713 for input in inputs:
3714 if not MadAnalysis5Card.events_can_be_reconstructed(input):
3715 continue
3716
3717 if warn_fifo(input):
3718 continue
3719 recasting_cmds.extend(get_import(input,'signal'))
3720 n_inputs += 1
3721
3722 recasting_cmds.append('set main.recast.card_path=%s'%recasting_card_path)
3723 recasting_cmds.append(submit_command%'Recasting')
3724 if n_inputs>0:
3725 cmds_list.append( ('Recasting',recasting_cmds))
3726
3727 return cmds_list
3728
3730 """A class object for the run_card for a (aMC@)NLO pocess"""
3731
3733 """define the default value"""
3734
3735 self.add_param('run_tag', 'tag_1', include=False)
3736 self.add_param('nevents', 10000)
3737 self.add_param('req_acc', -1.0, include=False)
3738 self.add_param('nevt_job', -1, include=False)
3739 self.add_param('event_norm', 'average')
3740
3741 self.add_param('req_acc_fo', 0.01, include=False)
3742 self.add_param('npoints_fo_grid', 5000, include=False)
3743 self.add_param('niters_fo_grid', 4, include=False)
3744 self.add_param('npoints_fo', 10000, include=False)
3745 self.add_param('niters_fo', 6, include=False)
3746
3747 self.add_param('iseed', 0)
3748 self.add_param('lpp1', 1, fortran_name='lpp(1)')
3749 self.add_param('lpp2', 1, fortran_name='lpp(2)')
3750 self.add_param('ebeam1', 6500.0, fortran_name='ebeam(1)')
3751 self.add_param('ebeam2', 6500.0, fortran_name='ebeam(2)')
3752 self.add_param('pdlabel', 'nn23nlo', allowed=['lhapdf', 'cteq6_m','cteq6_d','cteq6_l','cteq6l1', 'nn23lo','nn23lo1','nn23nlo'])
3753 self.add_param('lhaid', [244600],fortran_name='lhaPDFid')
3754 self.add_param('lhapdfsetname', ['internal_use_only'], system=True)
3755
3756 self.add_param('parton_shower', 'HERWIG6', fortran_name='shower_mc')
3757 self.add_param('shower_scale_factor',1.0)
3758 self.add_param('fixed_ren_scale', False)
3759 self.add_param('fixed_fac_scale', False)
3760 self.add_param('mur_ref_fixed', 91.118)
3761 self.add_param('muf1_ref_fixed', -1.0, hidden=True)
3762 self.add_param('muf_ref_fixed', 91.118)
3763 self.add_param('muf2_ref_fixed', -1.0, hidden=True)
3764 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")
3765 self.add_param('fixed_qes_scale', False, hidden=True)
3766 self.add_param('qes_ref_fixed', -1.0, hidden=True)
3767 self.add_param('mur_over_ref', 1.0)
3768 self.add_param('muf_over_ref', 1.0)
3769 self.add_param('muf1_over_ref', -1.0, hidden=True)
3770 self.add_param('muf2_over_ref', -1.0, hidden=True)
3771 self.add_param('qes_over_ref', -1.0, hidden=True)
3772 self.add_param('reweight_scale', [True], fortran_name='lscalevar')
3773 self.add_param('rw_rscale_down', -1.0, hidden=True)
3774 self.add_param('rw_rscale_up', -1.0, hidden=True)
3775 self.add_param('rw_fscale_down', -1.0, hidden=True)
3776 self.add_param('rw_fscale_up', -1.0, hidden=True)
3777 self.add_param('rw_rscale', [1.0,2.0,0.5], fortran_name='scalevarR')
3778 self.add_param('rw_fscale', [1.0,2.0,0.5], fortran_name='scalevarF')
3779 self.add_param('reweight_pdf', [False], fortran_name='lpdfvar')
3780 self.add_param('pdf_set_min', 244601, hidden=True)
3781 self.add_param('pdf_set_max', 244700, hidden=True)
3782 self.add_param('store_rwgt_info', False)
3783 self.add_param('systematics_program', 'none', include=False, hidden=True, comment='Choose which program to use for systematics computation: none, systematics')
3784 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.')
3785
3786
3787 self.add_param('ickkw', 0)
3788 self.add_param('bwcutoff', 15.0)
3789
3790 self.add_param('jetalgo', 1.0)
3791 self.add_param('jetradius', 0.7)
3792 self.add_param('ptj', 10.0 , cut=True)
3793 self.add_param('etaj', -1.0, cut=True)
3794 self.add_param('ptl', 0.0, cut=True)
3795 self.add_param('etal', -1.0, cut=True)
3796 self.add_param('drll', 0.0, cut=True)
3797 self.add_param('drll_sf', 0.0, cut=True)
3798 self.add_param('mll', 0.0, cut=True)
3799 self.add_param('mll_sf', 30.0, cut=True)
3800 self.add_param('ptgmin', 20.0, cut=True)
3801 self.add_param('etagamma', -1.0)
3802 self.add_param('r0gamma', 0.4)
3803 self.add_param('xn', 1.0)
3804 self.add_param('epsgamma', 1.0)
3805 self.add_param('isoem', True)
3806 self.add_param('maxjetflavor', 4, hidden=True)
3807 self.add_param('iappl', 0)
3808 self.add_param('lhe_version', 3, hidden=True, include=False)
3809
3810
3811 self.add_param('FO_LHE_weight_ratio',1e-3, hidden=True, system=True)
3812 self.add_param('FO_LHE_postprocessing',['grouping','random'],
3813 hidden=True, system=True, include=False)
3814
3815
3816 self.add_param('pt_min_pdg',{'__type__':0.}, include=False)
3817 self.add_param('pt_max_pdg',{'__type__':0.}, include=False)
3818 self.add_param('mxx_min_pdg',{'__type__':0.}, include=False)
3819 self.add_param('mxx_only_part_antipart', {'default':False}, include=False, hidden=True)
3820
3821
3822 self.add_param('pdg_cut',[0], hidden=True, system=True)
3823 self.add_param('ptmin4pdg',[0.], hidden=True, system=True)
3824 self.add_param('ptmax4pdg',[-1.], hidden=True, system=True)
3825 self.add_param('mxxmin4pdg',[0.], hidden=True, system=True)
3826 self.add_param('mxxpart_antipart', [False], hidden=True, system=True)
3827
3829 """check the validity of the various input"""
3830
3831 super(RunCardNLO, self).check_validity()
3832
3833
3834 if self['lpp1']==0 and self['lpp2']==0:
3835 if self['pdlabel']!='nn23nlo' or self['reweight_pdf']:
3836 self['pdlabel']='nn23nlo'
3837 self['reweight_pdf']=[False]
3838 logger.info('''Lepton-lepton collisions: ignoring PDF related parameters in the run_card.dat (pdlabel, lhaid, reweight_pdf, ...)''')
3839
3840
3841 if self['ickkw'] == 3:
3842
3843 scales=['fixed_ren_scale','fixed_fac_scale','fixed_QES_scale']
3844 for scale in scales:
3845 if self[scale]:
3846 logger.warning('''For consistency in the FxFx merging, \'%s\' has been set to false'''
3847 % scale,'$MG:BOLD')
3848 self[scale]= False
3849
3850 if len(self["dynamical_scale_choice"]) > 1 or self["dynamical_scale_choice"][0] != -1:
3851 self["dynamical_scale_choice"] = [-1]
3852 self["reweight_scale"]=[self["reweight_scale"][0]]
3853 logger.warning('''For consistency in the FxFx merging, dynamical_scale_choice has been set to -1 (default)'''
3854 ,'$MG:BOLD')
3855
3856
3857 jetparams=['jetradius','jetalgo']
3858 for jetparam in jetparams:
3859 if float(self[jetparam]) != 1.0:
3860 logger.info('''For consistency in the FxFx merging, \'%s\' has been set to 1.0'''
3861 % jetparam ,'$MG:BOLD')
3862 self[jetparam] = 1.0
3863 elif self['ickkw'] == -1 and (self["dynamical_scale_choice"][0] != -1 or
3864 len(self["dynamical_scale_choice"]) > 1):
3865 self["dynamical_scale_choice"] = [-1]
3866 self["reweight_scale"]=[self["reweight_scale"][0]]
3867 logger.warning('''For consistency with the jet veto, the scale which will be used is ptj. dynamical_scale_choice will be set at -1.'''
3868 ,'$MG:BOLD')
3869
3870
3871 if self['iappl'] != 0 and self['pdlabel'].lower() != 'lhapdf':
3872 raise InvalidRunCard('APPLgrid generation only possible with the use of LHAPDF')
3873 if self['iappl'] != 0 and not self['reweight_scale']:
3874 raise InvalidRunCard('APPLgrid generation only possible with including' +\
3875 ' the reweighting to get scale dependence')
3876
3877
3878 if self['qes_ref_fixed'] == -1.0:
3879 self['qes_ref_fixed']=self['mur_ref_fixed']
3880 if self['qes_over_ref'] == -1.0:
3881 self['qes_over_ref']=self['mur_over_ref']
3882 if self['muf1_over_ref'] != -1.0 and self['muf1_over_ref'] == self['muf2_over_ref']:
3883 self['muf_over_ref']=self['muf1_over_ref']
3884 if self['muf1_over_ref'] == -1.0:
3885 self['muf1_over_ref']=self['muf_over_ref']
3886 if self['muf2_over_ref'] == -1.0:
3887 self['muf2_over_ref']=self['muf_over_ref']
3888 if self['muf1_ref_fixed'] != -1.0 and self['muf1_ref_fixed'] == self['muf2_ref_fixed']:
3889 self['muf_ref_fixed']=self['muf1_ref_fixed']
3890 if self['muf1_ref_fixed'] == -1.0:
3891 self['muf1_ref_fixed']=self['muf_ref_fixed']
3892 if self['muf2_ref_fixed'] == -1.0:
3893 self['muf2_ref_fixed']=self['muf_ref_fixed']
3894
3895 if (self['rw_rscale_down'] != -1.0 and ['rw_rscale_down'] not in self['rw_rscale']) or\
3896 (self['rw_rscale_up'] != -1.0 and ['rw_rscale_up'] not in self['rw_rscale']):
3897 self['rw_rscale']=[1.0,self['rw_rscale_up'],self['rw_rscale_down']]
3898 if (self['rw_fscale_down'] != -1.0 and ['rw_fscale_down'] not in self['rw_fscale']) or\
3899 (self['rw_fscale_up'] != -1.0 and ['rw_fscale_up'] not in self['rw_fscale']):
3900 self['rw_fscale']=[1.0,self['rw_fscale_up'],self['rw_fscale_down']]
3901
3902
3903 if any(self['reweight_pdf']):
3904
3905 if self['pdlabel'] != "lhapdf":
3906 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.'
3907
3908
3909 if self['pdlabel'] != "lhapdf":
3910 self['reweight_pdf']=[self['reweight_pdf'][0]]
3911 self['lhaid']=[self['lhaid'][0]]
3912
3913
3914 if self['fixed_ren_scale'] and self['fixed_fac_scale']:
3915 self['reweight_scale']=[self['reweight_scale'][0]]
3916 self['dynamical_scale_choice']=[0]
3917
3918
3919
3920
3921 if len(self['reweight_pdf']) == 1 and len(self['lhaid']) != 1:
3922 self['reweight_pdf']=self['reweight_pdf']*len(self['lhaid'])
3923 logger.warning("Setting 'reweight_pdf' for all 'lhaid' to %s" % self['reweight_pdf'][0])
3924 if len(self['reweight_scale']) == 1 and len(self['dynamical_scale_choice']) != 1:
3925 self['reweight_scale']=self['reweight_scale']*len(self['dynamical_scale_choice'])
3926 logger.warning("Setting 'reweight_scale' for all 'dynamical_scale_choice' to %s" % self['reweight_pdf'][0])
3927
3928
3929 if len(self['lhaid']) != len(set(self['lhaid'])):
3930 raise InvalidRunCard, "'lhaid' has two or more identical entries. They have to be all different for the code to work correctly."
3931 if len(self['dynamical_scale_choice']) != len(set(self['dynamical_scale_choice'])):
3932 raise InvalidRunCard, "'dynamical_scale_choice' has two or more identical entries. They have to be all different for the code to work correctly."
3933
3934
3935 if len(self['reweight_pdf']) != len(self['lhaid']):
3936 raise InvalidRunCard, "'reweight_pdf' and 'lhaid' lists should have the same length"
3937 if len(self['reweight_scale']) != len(self['dynamical_scale_choice']):
3938 raise InvalidRunCard, "'reweight_scale' and 'dynamical_scale_choice' lists should have the same length"
3939 if len(self['dynamical_scale_choice']) > 10 :
3940 raise InvalidRunCard, "Length of list for 'dynamical_scale_choice' too long: max is 10."
3941 if len(self['lhaid']) > 25 :
3942 raise InvalidRunCard, "Length of list for 'lhaid' too long: max is 25."
3943 if len(self['rw_rscale']) > 9 :
3944 raise InvalidRunCard, "Length of list for 'rw_rscale' too long: max is 9."
3945 if len(self['rw_fscale']) > 9 :
3946 raise InvalidRunCard, "Length of list for 'rw_fscale' too long: max is 9."
3947
3948 if 1.0 not in self['rw_rscale']:
3949 logger.warning("'1.0' has to be part of 'rw_rscale', adding it")
3950 self['rw_rscale'].insert(0,1.0)
3951 if 1.0 not in self['rw_fscale']:
3952 logger.warning("'1.0' has to be part of 'rw_fscale', adding it")
3953 self['rw_fscale'].insert(0,1.0)
3954 if self['rw_rscale'][0] != 1.0 and 1.0 in self['rw_rscale']:
3955 a=self['rw_rscale'].index(1.0)
3956 self['rw_rscale'][0],self['rw_rscale'][a]=self['rw_rscale'][a],self['rw_rscale'][0]
3957 if self['rw_fscale'][0] != 1.0 and 1.0 in self['rw_fscale']:
3958 a=self['rw_fscale'].index(1.0)
3959 self['rw_fscale'][0],self['rw_fscale'][a]=self['rw_fscale'][a],self['rw_fscale'][0]
3960
3961 if len(self['rw_rscale']) != len(set(self['rw_rscale'])):
3962 raise InvalidRunCard, "'rw_rscale' has two or more identical entries. They have to be all different for the code to work correctly."
3963 if len(self['rw_fscale']) != len(set(self['rw_fscale'])):
3964 raise InvalidRunCard, "'rw_fscale' has two or more identical entries. They have to be all different for the code to work correctly."
3965
3966
3968
3969
3970 pdg_to_cut = set(self['pt_min_pdg'].keys() +self['pt_max_pdg'].keys()+
3971 self['mxx_min_pdg'].keys()+ self['mxx_only_part_antipart'].keys())
3972 pdg_to_cut.discard('__type__')
3973 pdg_to_cut.discard('default')
3974 if len(pdg_to_cut)>25:
3975 raise Exception, "Maximum 25 different PDGs are allowed for PDG specific cut"
3976
3977 if any(int(pdg)<0 for pdg in pdg_to_cut):
3978 logger.warning('PDG specific cuts are always applied symmetrically on particle/anti-particle. Always use positve PDG codes')
3979 raise MadGraph5Error, 'Some PDG specific cuts are defined with negative PDG codes'
3980
3981
3982 if any(pdg in pdg_to_cut for pdg in [21,22,11,13,15]+ range(self['maxjetflavor']+1)):
3983
3984 raise Exception, "Can not use PDG related cuts for massless SM particles/leptons"
3985 if pdg_to_cut:
3986 self['pdg_cut'] = list(pdg_to_cut)
3987 self['ptmin4pdg'] = []
3988 self['ptmax4pdg'] = []
3989 self['mxxmin4pdg'] = []
3990 self['mxxpart_antipart'] = []
3991 for pdg in self['pdg_cut']:
3992 for var in ['pt','mxx']:
3993 for minmax in ['min', 'max']:
3994 if var == 'mxx' and minmax == 'max':
3995 continue
3996 new_var = '%s%s4pdg' % (var, minmax)
3997 old_var = '%s_%s_pdg' % (var, minmax)
3998 default = 0. if minmax=='min' else -1.
3999 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4000
4001 old_var = 'mxx_only_part_antipart'
4002 new_var = 'mxxpart_antipart'
4003 if 'default' in self[old_var]:
4004 default = self[old_var]['default']
4005 self[new_var].append(self[old_var][str(pdg)] if str(pdg) in self[old_var] else default)
4006 else:
4007 if str(pdg) not in self[old_var]:
4008 raise Exception("no default value defined for %s and no value defined for pdg %s" % (old_var, pdg))
4009 self[new_var].append(self[old_var][str(pdg)])
4010 else:
4011 self['pdg_cut'] = [0]
4012 self['ptmin4pdg'] = [0.]
4013 self['ptmax4pdg'] = [-1.]
4014 self['mxxmin4pdg'] = [0.]
4015 self['mxxpart_antipart'] = [False]
4016
4017 - def write(self, output_file, template=None, python_template=False, **opt):
4018 """Write the run_card in output_file according to template
4019 (a path to a valid run_card)"""
4020
4021 if not template:
4022 if not MADEVENT:
4023 template = pjoin(MG5DIR, 'Template', 'NLO', 'Cards',
4024 'run_card.dat')
4025 python_template = True
4026 else:
4027 template = pjoin(MEDIR, 'Cards', 'run_card_default.dat')
4028 python_template = False
4029
4030 super(RunCardNLO, self).write(output_file, template=template,
4031 python_template=python_template, **opt)
4032
4033
4035 """Rules
4036 e+ e- beam -> lpp:0 ebeam:500
4037 p p beam -> set maxjetflavor automatically
4038 """
4039
4040
4041 beam_id = set()
4042 for proc in proc_def:
4043 for leg in proc['legs']:
4044 if not leg['state']:
4045 beam_id.add(leg['id'])
4046 if any(i in beam_id for i in [1,-1,2,-2,3,-3,4,-4,5,-5,21,22]):
4047 maxjetflavor = max([4]+[abs(i) for i in beam_id if -7< i < 7])
4048 self['maxjetflavor'] = maxjetflavor
4049 pass
4050 elif 11 in beam_id or -11 in beam_id:
4051 self['lpp1'] = 0
4052 self['lpp2'] = 0
4053 self['ebeam1'] = 500
4054 self['ebeam2'] = 500
4055 else:
4056 self['lpp1'] = 0
4057 self['lpp2'] = 0
4058
4059 if proc_characteristic['ninitial'] == 1:
4060
4061 self.remove_all_cut()
4062
4066 """ a class for storing/dealing with the file MadLoopParam.dat
4067 contains a parser to read it, facilities to write a new file,...
4068 """
4069
4070 _ID_reduction_tool_map = {1:'CutTools',
4071 2:'PJFry++',
4072 3:'IREGI',
4073 4:'Golem95',
4074 5:'Samurai',
4075 6:'Ninja',
4076 7:'COLLIER'}
4077
4079 """initialize the directory to the default value"""
4080
4081 self.add_param("MLReductionLib", "6|7|1")
4082 self.add_param("IREGIMODE", 2)
4083 self.add_param("IREGIRECY", True)
4084 self.add_param("CTModeRun", -1)
4085 self.add_param("MLStabThres", 1e-3)
4086 self.add_param("NRotations_DP", 0)
4087 self.add_param("NRotations_QP", 0)
4088 self.add_param("ImprovePSPoint", 2)
4089 self.add_param("CTLoopLibrary", 2)
4090 self.add_param("CTStabThres", 1e-2)
4091 self.add_param("CTModeInit", 1)
4092 self.add_param("CheckCycle", 3)
4093 self.add_param("MaxAttempts", 10)
4094 self.add_param("ZeroThres", 1e-9)
4095 self.add_param("OSThres", 1.0e-8)
4096 self.add_param("DoubleCheckHelicityFilter", True)
4097 self.add_param("WriteOutFilters", True)
4098 self.add_param("UseLoopFilter", False)
4099 self.add_param("HelicityFilterLevel", 2)
4100 self.add_param("LoopInitStartOver", False)
4101 self.add_param("HelInitStartOver", False)
4102 self.add_param("UseQPIntegrandForNinja", True)
4103 self.add_param("UseQPIntegrandForCutTools", True)
4104 self.add_param("COLLIERMode", 1)
4105 self.add_param("COLLIERComputeUVpoles", True)
4106 self.add_param("COLLIERComputeIRpoles", True)
4107 self.add_param("COLLIERRequiredAccuracy", 1.0e-8)
4108 self.add_param("COLLIERCanOutput",False)
4109 self.add_param("COLLIERGlobalCache",-1)
4110 self.add_param("COLLIERUseCacheForPoles",False)
4111 self.add_param("COLLIERUseInternalStabilityTest",True)
4112
4113 - def read(self, finput):
4114 """Read the input file, this can be a path to a file,
4115 a file object, a str with the content of the file."""
4116
4117 if isinstance(finput, str):
4118 if "\n" in finput:
4119 finput = finput.split('\n')
4120 elif os.path.isfile(finput):
4121 finput = open(finput)
4122 else:
4123 raise Exception, "No such file %s" % input
4124
4125 previous_line= ''
4126 for line in finput:
4127 if previous_line.startswith('#'):
4128 name = previous_line[1:].split()[0]
4129 value = line.strip()
4130 if len(value) and value[0] not in ['#', '!']:
4131 self.__setitem__(name, value, change_userdefine=True)
4132 previous_line = line
4133
4134
4135 - def write(self, outputpath, template=None,commentdefault=False):
4136
4137 if not template:
4138 if not MADEVENT:
4139 template = pjoin(MG5DIR, 'Template', 'loop_material', 'StandAlone',
4140 'Cards', 'MadLoopParams.dat')
4141 else:
4142 template = pjoin(MEDIR, 'Cards', 'MadLoopParams_default.dat')
4143 fsock = open(template, 'r')
4144 template = fsock.readlines()
4145 fsock.close()
4146
4147 if isinstance(outputpath, str):
4148 output = open(outputpath, 'w')
4149 else:
4150 output = outputpath
4151
4152 def f77format(value):
4153 if isinstance(value, bool):
4154 if value:
4155 return '.true.'
4156 else:
4157 return '.false.'
4158 elif isinstance(value, int):
4159 return value
4160 elif isinstance(value, float):
4161 tmp ='%e' % value
4162 return tmp.replace('e','d')
4163 elif isinstance(value, str):
4164 return value
4165 else:
4166 raise Exception, "Can not format input %s" % type(value)
4167
4168 name = ''
4169 done = set()
4170 for line in template:
4171 if name:
4172 done.add(name)
4173 if commentdefault and name.lower() not in self.user_set :
4174 output.write('!%s\n' % f77format(self[name]))
4175 else:
4176 output.write('%s\n' % f77format(self[name]))
4177 name=''
4178 continue
4179 elif line.startswith('#'):
4180 name = line[1:].split()[0]
4181 output.write(line)
4182