1 from __future__ import division
2 import collections
3 import random
4 import re
5 import numbers
6 import math
7 import time
8 import os
9 import shutil
10 import sys
11
12 pjoin = os.path.join
13
14 if '__main__' == __name__:
15 import sys
16 sys.path.append('../../')
17 import misc
18 import logging
19 import gzip
20 import banner as banner_mod
21 logger = logging.getLogger("madgraph.lhe_parser")
22
23 -class Particle(object):
24 """ """
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 - def __init__(self, line=None, event=None):
46 """ """
47
48 if isinstance(line, Particle):
49 for key in line.__dict__:
50 setattr(self, key, getattr(line, key))
51 if event:
52 self.event = event
53 return
54
55 self.event = event
56 self.event_id = len(event)
57
58 self.pid = 0
59 self.status = 0
60 self.mother1 = None
61 self.mother2 = None
62 self.color1 = 0
63 self.color2 = None
64 self.px = 0
65 self.py = 0
66 self.pz = 0
67 self.E = 0
68 self.mass = 0
69 self.vtim = 0
70 self.helicity = 9
71 self.rwgt = 0
72 self.comment = ''
73
74 if line:
75 self.parse(line)
76
77 @property
79 "convenient alias"
80 return self.pid
81
82 - def parse(self, line):
83 """parse the line"""
84
85 args = line.split()
86 keys = ['pid', 'status','mother1','mother2','color1', 'color2', 'px','py','pz','E',
87 'mass','vtim','helicity']
88
89 for key,value in zip(keys,args):
90 setattr(self, key, float(value))
91 self.pid = int(self.pid)
92
93 self.comment = ' '.join(args[len(keys):])
94 if self.comment.startswith(('|','#')):
95 self.comment = self.comment[1:]
96
97
98
99
101 """string representing the particles"""
102 return " %8d %2d %4d %4d %4d %4d %+13.10e %+13.10e %+13.10e %14.10e %14.10e %10.4e %10.4e" \
103 % (self.pid,
104 self.status,
105 (self.mother1 if isinstance(self.mother1, numbers.Number) else self.mother1.event_id+1) if self.mother1 else 0,
106 (self.mother2 if isinstance(self.mother2, numbers.Number) else self.mother2.event_id+1) if self.mother2 else 0,
107 self.color1,
108 self.color2,
109 self.px,
110 self.py,
111 self.pz,
112 self.E,
113 self.mass,
114 self.vtim,
115 self.helicity)
116
117 - def __eq__(self, other):
118
119 if not isinstance(other, Particle):
120 return False
121 if self.pid == other.pid and \
122 self.status == other.status and \
123 self.mother1 == other.mother1 and \
124 self.mother2 == other.mother2 and \
125 self.color1 == other.color1 and \
126 self.color2 == other.color2 and \
127 self.px == other.px and \
128 self.py == other.py and \
129 self.pz == other.pz and \
130 self.E == other.E and \
131 self.mass == other.mass and \
132 self.vtim == other.vtim and \
133 self.helicity == other.helicity:
134 return True
135 return False
136
137 - def set_momentum(self, momentum):
138
139 self.E = momentum.E
140 self.px = momentum.px
141 self.py = momentum.py
142 self.pz = momentum.pz
143
144 - def add_decay(self, decay_event):
145 """associate to this particle the decay in the associate event"""
146
147 return self.event.add_decay_to_particle(self.event_id, decay_event)
148
149 - def __repr__(self):
150 return 'Particle("%s", event=%s)' % (str(self), self.event)
151
154 """A class to allow to read both gzip and not gzip file"""
155
156 eventgroup = False
157
158 - def __new__(self, path, mode='r', *args, **opt):
159
160 if not path.endswith(".gz"):
161 return file.__new__(EventFileNoGzip, path, mode, *args, **opt)
162 elif mode == 'r' and not os.path.exists(path) and os.path.exists(path[:-3]):
163 return EventFile.__new__(EventFileNoGzip, path[:-3], mode, *args, **opt)
164 else:
165 try:
166 return gzip.GzipFile.__new__(EventFileGzip, path, mode, *args, **opt)
167 except IOError, error:
168 raise
169 except Exception, error:
170 if mode == 'r':
171 misc.gunzip(path)
172 return file.__new__(EventFileNoGzip, path[:-3], mode, *args, **opt)
173
174
175 - def __init__(self, path, mode='r', *args, **opt):
176 """open file and read the banner [if in read mode]"""
177
178 self.parsing = True
179
180 try:
181 super(EventFile, self).__init__(path, mode, *args, **opt)
182 except IOError:
183 if '.gz' in path and isinstance(self, EventFileNoGzip) and\
184 mode == 'r' and os.path.exists(path[:-3]):
185 super(EventFile, self).__init__(path[:-3], mode, *args, **opt)
186 else:
187 raise
188
189 self.banner = ''
190 if mode == 'r':
191 line = ''
192 while '</init>' not in line.lower():
193 try:
194 line = super(EventFile, self).next()
195 except StopIteration:
196 self.seek(0)
197 self.banner = ''
198 break
199 if "<event" in line.lower():
200 self.seek(0)
201 self.banner = ''
202 break
203
204 self.banner += line
205
215
216 @property
218 """return the cross-section of the file #from the banner"""
219 try:
220 return self._cross
221 except Exception:
222 pass
223
224 onebanner = self.get_banner()
225 self._cross = onebanner.get_cross()
226 return self._cross
227
229 if self.closed:
230 return 0
231 if hasattr(self,"len"):
232 return self.len
233
234 init_pos = self.tell()
235 self.seek(0)
236 nb_event=0
237 with misc.TMP_variable(self, 'parsing', False):
238 for _ in self:
239 nb_event +=1
240 self.len = nb_event
241 self.seek(init_pos)
242 return self.len
243
245 """get next event"""
246
247 if not self.eventgroup:
248 text = ''
249 line = ''
250 mode = 0
251 while '</event>' not in line:
252 line = super(EventFile, self).next()
253 if '<event' in line:
254 mode = 1
255 text = ''
256 if mode:
257 text += line
258
259 if self.parsing:
260 return Event(text)
261 else:
262 return text
263 else:
264 events = []
265 text = ''
266 line = ''
267 mode = 0
268 while '</eventgroup>' not in line:
269 line = super(EventFile, self).next()
270 if '<eventgroup' in line:
271 events=[]
272 text = ''
273 elif '<event' in line:
274 text=''
275 mode=1
276 elif '</event>' in line:
277 if self.parsing:
278 events.append(Event(text))
279 else:
280 events.append(text)
281 text = ''
282 mode = 0
283 if mode:
284 text += line
285 return events
286
287
289 """ scan once the file to return
290 - the list of the hightest weight (of size trunc_error*NB_EVENT
291 - the cross-section by type of process
292 - the total number of events in the file
293 """
294
295
296
297 self.seek(0)
298 all_wgt = []
299 cross = collections.defaultdict(int)
300 nb_event = 0
301 for event in self:
302 nb_event +=1
303 wgt = get_wgt(event)
304 cross['all'] += wgt
305 cross['abs'] += abs(wgt)
306 cross[event.ievent] += wgt
307 all_wgt.append(abs(wgt))
308
309 if nb_event % 20000 == 0:
310 all_wgt.sort()
311
312 nb_keep = max(20, int(nb_event*trunc_error*15))
313 all_wgt = all_wgt[-nb_keep:]
314
315
316 all_wgt.sort()
317
318 nb_keep = max(20, int(nb_event*trunc_error*10))
319 all_wgt = all_wgt[-nb_keep:]
320 self.seek(0)
321 return all_wgt, cross, nb_event
322
324 """ write a single events or a list of event
325 if self.eventgroup is ON, then add <eventgroup> around the lists of events
326 """
327 if isinstance(event, Event):
328 if self.eventgroup:
329 self.write('<eventgroup>\n%s\n<eventgroup>\n' % event)
330 elif isinstance(event, list):
331 if self.eventgroup:
332 self.write('<eventgroup>\n')
333 for evt in event:
334 self.write(str(evt))
335 if self.eventgroup:
336 self.write('</eventgroup>\n')
337
338 - def unweight(self, outputpath, get_wgt=None, max_wgt=0, trunc_error=0,
339 event_target=0, log_level=logging.INFO, normalization='average'):
340 """unweight the current file according to wgt information wgt.
341 which can either be a fct of the event or a tag in the rwgt list.
342 max_wgt allow to do partial unweighting.
343 trunc_error allow for dynamical partial unweighting
344 event_target reweight for that many event with maximal trunc_error.
345 (stop to write event when target is reached)
346 """
347 if not get_wgt:
348 def weight(event):
349 return event.wgt
350 get_wgt = weight
351 unwgt_name = "central weight"
352 elif isinstance(get_wgt, str):
353 unwgt_name =get_wgt
354 def get_wgt(event):
355 event.parse_reweight()
356 return event.reweight_data[unwgt_name]
357 else:
358 unwgt_name = get_wgt.func_name
359
360
361 if hasattr(self, "written_weight"):
362 written_weight = lambda x: math.copysign(self.written_weight,float(x))
363 else:
364 written_weight = lambda x: x
365
366 all_wgt, cross, nb_event = self.initialize_unweighting(get_wgt, trunc_error)
367
368
369 def max_wgt_for_trunc(trunc):
370 """find the weight with the maximal truncation."""
371
372 xsum = 0
373 i=1
374 while (xsum - all_wgt[-i] * (i-1) <= cross['abs'] * trunc):
375 max_wgt = all_wgt[-i]
376 xsum += all_wgt[-i]
377 i +=1
378 if i == len(all_wgt):
379 break
380
381 return max_wgt
382
383
384
385 if not max_wgt:
386 if trunc_error == 0 or len(all_wgt)<2 or event_target:
387 max_wgt = all_wgt[-1]
388 else:
389 max_wgt = max_wgt_for_trunc(trunc_error)
390
391
392 if self.banner:
393 try:
394 import internal
395 except:
396 import madgraph.various.banner as banner_module
397 else:
398 import internal.banner as banner_module
399 if not isinstance(self.banner, banner_module.Banner):
400 banner = self.get_banner()
401
402 banner.modify_init_cross(cross)
403
404 banner["unweight"] = "unweighted by %s" % unwgt_name
405 else:
406 banner = self.banner
407
408 curr_strategy = banner.get_lha_strategy()
409 if normalization in ['unit', 'sum']:
410 strategy = 3
411 else:
412 strategy = 4
413 if curr_strategy >0:
414 banner.set_lha_strategy(abs(strategy))
415 else:
416 banner.set_lha_strategy(-1*abs(strategy))
417
418
419 nb_try = 20
420 nb_keep = 0
421 for i in range(nb_try):
422 self.seek(0)
423 if event_target:
424 if i==0:
425 max_wgt = max_wgt_for_trunc(0)
426 else:
427
428 efficiency = nb_keep/nb_event
429 needed_efficiency = event_target/nb_event
430 last_max_wgt = max_wgt
431 needed_max_wgt = last_max_wgt * efficiency / needed_efficiency
432
433 min_max_wgt = max_wgt_for_trunc(trunc_error)
434 max_wgt = max(min_max_wgt, needed_max_wgt)
435 max_wgt = min(max_wgt, all_wgt[-1])
436 if max_wgt == last_max_wgt:
437 if nb_keep <= event_target and log_level>=10:
438 logger.log(log_level+10,"fail to reach target %s", event_target)
439 break
440 else:
441 break
442
443
444 if outputpath:
445 outfile = EventFile(outputpath, "w")
446
447
448 if self.banner and outputpath:
449 banner.write(outfile, close_tag=False)
450
451
452 nb_keep = 0
453 trunc_cross = 0
454 for event in self:
455 r = random.random()
456 wgt = get_wgt(event)
457 if abs(wgt) < r * max_wgt:
458 continue
459 elif wgt > 0:
460 nb_keep += 1
461 event.wgt = written_weight(max(wgt, max_wgt))
462 if abs(wgt) > max_wgt:
463 trunc_cross += abs(wgt) - max_wgt
464 if event_target ==0 or nb_keep <= event_target:
465 if outputpath:
466 outfile.write(str(event))
467
468 elif wgt < 0:
469 nb_keep += 1
470 event.wgt = -1* written_weight(max(abs(wgt), max_wgt))
471 if abs(wgt) > max_wgt:
472 trunc_cross += abs(wgt) - max_wgt
473 if outputpath and (event_target ==0 or nb_keep <= event_target):
474 outfile.write(str(event))
475
476 if event_target and nb_keep > event_target:
477 if not outputpath:
478
479 continue
480 elif event_target and i != nb_try-1 and nb_keep >= event_target *1.05:
481 outfile.write("</LesHouchesEvents>\n")
482 outfile.close()
483
484 continue
485 else:
486 outfile.write("</LesHouchesEvents>\n")
487 outfile.close()
488 break
489 elif event_target == 0:
490 if outputpath:
491 outfile.write("</LesHouchesEvents>\n")
492 outfile.close()
493 break
494 elif outputpath:
495 outfile.write("</LesHouchesEvents>\n")
496 outfile.close()
497
498
499 else:
500
501 logger.log(log_level+10,"fail to reach target event %s (iteration=%s)", event_target,i)
502
503
504
505
506 if event_target:
507 nb_events_unweighted = nb_keep
508 nb_keep = min( event_target, nb_keep)
509 else:
510 nb_events_unweighted = nb_keep
511
512 logger.log(log_level, "write %i event (efficiency %.2g %%, truncation %.2g %%) after %i iteration(s)",
513 nb_keep, nb_events_unweighted/nb_event*100, trunc_cross/cross['abs']*100, i)
514
515
516 if nb_keep != event_target and hasattr(self, "written_weight") and strategy !=4:
517 written_weight = lambda x: math.copysign(self.written_weight*event_target/nb_keep, float(x))
518 startfile = EventFile(outputpath)
519 tmpname = pjoin(os.path.dirname(outputpath), "wgtcorrected_"+ os.path.basename(outputpath))
520 outfile = EventFile(tmpname, "w")
521 outfile.write(startfile.banner)
522 for event in startfile:
523 event.wgt = written_weight(event.wgt)
524 outfile.write(str(event))
525 outfile.write("</LesHouchesEvents>\n")
526 startfile.close()
527 outfile.close()
528 shutil.move(tmpname, outputpath)
529
530
531
532
533 self.max_wgt = max_wgt
534 return nb_keep
535
537 """ apply one or more fct on all event. """
538
539 opt= {"print_step": 5000, "maxevent":float("inf"),'no_output':False}
540 opt.update(opts)
541 start = time.time()
542 nb_fct = len(fcts)
543 out = []
544 for i in range(nb_fct):
545 out.append([])
546 self.seek(0)
547 nb_event = 0
548 for event in self:
549 nb_event += 1
550 if opt["print_step"] and (nb_event % opt["print_step"]) == 0:
551 if hasattr(self,"len"):
552 print("currently at %s/%s event [%is]" % (nb_event, self.len, time.time()-start))
553 else:
554 print("currently at %s event [%is]" % (nb_event, time.time()-start))
555 for i in range(nb_fct):
556 value = fcts[i](event)
557 if not opt['no_output']:
558 out[i].append(value)
559 if nb_event > opt['maxevent']:
560 break
561 if nb_fct == 1:
562 return out[0]
563 else:
564 return out
565
566 - def split(self, nb_event=0, partition=None, cwd=os.path.curdir, zip=False):
567 """split the file in multiple file. Do not change the weight!"""
568
569 nb_file = -1
570 for i, event in enumerate(self):
571 if (not (partition is None) and i==sum(partition[:nb_file+1])) or \
572 (partition is None and i % nb_event == 0):
573 if i:
574
575 current.write('</LesHouchesEvent>\n')
576 current.close()
577
578 nb_file +=1
579
580 if not partition is None and (nb_file+1>len(partition)):
581 return nb_file
582 if zip:
583 current = EventFile(pjoin(cwd,'%s_%s.lhe.gz' % (self.name, nb_file)),'w')
584 else:
585 current = open(pjoin(cwd,'%s_%s.lhe' % (self.name, nb_file)),'w')
586 current.write(self.banner)
587 current.write(str(event))
588 if i!=0:
589 current.write('</LesHouchesEvent>\n')
590 current.close()
591 return nb_file +1
592
593 - def update_HwU(self, hwu, fct, name='lhe', keep_wgt=False, maxevents=sys.maxint):
594 """take a HwU and add this event file for the function fct"""
595
596 if not isinstance(hwu, list):
597 hwu = [hwu]
598
599 class HwUUpdater(object):
600
601 def __init__(self, fct, keep_wgt):
602
603 self.fct = fct
604 self.first = True
605 self.keep_wgt = keep_wgt
606
607 def add(self, event):
608
609 value = self.fct(event)
610
611 if self.first:
612 for h in hwu:
613
614 if isinstance(value, dict):
615 h.add_line(value.keys())
616 else:
617
618 h.add_line(name)
619 if self.keep_wgt is True:
620 event.parse_reweight()
621 h.add_line(['%s_%s' % (name, key)
622 for key in event.reweight_data])
623 elif self.keep_wgt:
624 h.add_line(self.keep_wgt.values())
625 self.first = False
626
627 for h in hwu:
628 if isinstance(value, tuple):
629 h.addEvent(value[0], value[1])
630 else:
631 h.addEvent(value,{name:event.wgt})
632 if self.keep_wgt:
633 event.parse_reweight()
634 if self.keep_wgt is True:
635 data = dict(('%s_%s' % (name, key),event.reweight_data[key])
636 for key in event.reweight_data)
637 h.addEvent(value, data)
638 else:
639 data = dict(( value,event.reweight_data[key])
640 for key,value in self.keep_wgt.items())
641 h.addEvent(value, data)
642
643
644
645 self.apply_fct_on_event(HwUUpdater(fct,keep_wgt).add, no_output=True,maxevent=maxevents)
646 return hwu
647
649 """take the lhe file and add the matchscale from the pythia_input file"""
650
651 if pythia_input:
652 def next_data():
653 for line in open(pythia_input):
654 if line.startswith('#'):
655 continue
656 data = line.split()
657 print (int(data[0]), data[-3], data[-2], data[-1])
658 yield (int(data[0]), data[-3], data[-2], data[-1])
659 else:
660 def next_data():
661 i=0
662 while 1:
663 yield [i,0,0,0]
664 i+=1
665 sys_iterator = next_data()
666
667 self.seek(0)
668 out = open(out_path,'w')
669
670 pdf_pattern = re.compile(r'''<init>(.*)</init>''', re.M+re.S)
671 init = pdf_pattern.findall(self.banner)[0].split('\n',2)[1]
672 id1, id2, _, _, _, _, pdf1,pdf2,_,_ = init.split()
673 id = [int(id1), int(id2)]
674 type = []
675 for i in range(2):
676 if abs(id[i]) == 2212:
677 if i > 0:
678 type.append(1)
679 else:
680 type.append(-1)
681 else:
682 type.append(0)
683 pdf = max(int(pdf1),int(pdf2))
684
685 out.write("<header>\n" + \
686 "<orgpdf>%i</orgpdf>\n" % pdf + \
687 "<beams> %s %s</beams>\n" % tuple(type) + \
688 "</header>\n")
689
690
691 nevt, smin, smax, scomp = sys_iterator.next()
692 for i, orig_event in enumerate(self):
693 if i < nevt:
694 continue
695 new_event = Event()
696 sys = orig_event.parse_syscalc_info()
697 new_event.syscalc_data = sys
698 if smin:
699 new_event.syscalc_data['matchscale'] = "%s %s %s" % (smin, scomp, smax)
700 out.write(str(new_event), nevt)
701 try:
702 nevt, smin, smax, scomp = sys_iterator.next()
703 except StopIteration:
704 break
705
706
707
708
709
710
711
712
713 -class EventFileGzip(EventFile, gzip.GzipFile):
714 """A way to read/write a gzipped lhef event"""
715
717 """A way to read a standard event file"""
718
720 """a class to read simultaneously multiple file and read them in mixing them.
721 Unweighting can be done at the same time.
722 The number of events in each file need to be provide in advance
723 (if not provide the file is first read to find that number"""
724
725 - def __new__(cls, start_list=[],parse=True):
727
728 - def __init__(self, start_list=[], parse=True):
729 """if trunc_error is define here then this allow
730 to only read all the files twice and not three times."""
731 self.files = []
732 self.parsefile = parse
733 self.banner = ''
734 self.initial_nb_events = []
735 self.total_event_in_files = 0
736 self.curr_nb_events = []
737 self.allcross = []
738 self.error = []
739 self.across = []
740 self.scales = []
741 if start_list:
742 if parse:
743 for p in start_list:
744 self.add(p)
745 else:
746 self.files = start_list
747 self._configure = False
748
749 - def close(self,*args,**opts):
752
753 - def add(self, path, cross, error, across, nb_event=0, scale=1):
754 """ add a file to the pool, across allow to reweight the sum of weight
755 in the file to the given cross-section
756 """
757
758 if across == 0:
759
760 return
761
762 obj = EventFile(path)
763 obj.eventgroup = self.eventgroup
764 if len(self.files) == 0 and not self.banner:
765 self.banner = obj.banner
766 self.curr_nb_events.append(0)
767 self.initial_nb_events.append(0)
768 self.allcross.append(cross)
769 self.across.append(across)
770 self.error.append(error)
771 self.scales.append(scale)
772 self.files.append(obj)
773 if nb_event:
774 obj.len = nb_event
775 self._configure = False
776 return obj
777
780
782
783 if not self._configure:
784 self.configure()
785
786 remaining_event = self.total_event_in_files - sum(self.curr_nb_events)
787 if remaining_event == 0:
788 raise StopIteration
789
790 nb_event = random.randint(1, remaining_event)
791 sum_nb=0
792 for i, obj in enumerate(self.files):
793 sum_nb += self.initial_nb_events[i] - self.curr_nb_events[i]
794 if nb_event <= sum_nb:
795 self.curr_nb_events[i] += 1
796 event = obj.next()
797 if not self.eventgroup:
798 event.sample_scale = self.scales[i]
799 else:
800 for evt in event:
801 evt.sample_scale = self.scales[i]
802 return event
803 else:
804 raise Exception
805
806
808 """define the part of the init_banner"""
809
810 if not self.banner:
811 return
812
813
814 grouped_cross = {}
815 grouped_error = {}
816 for i,ff in enumerate(self.files):
817 filename = ff.name
818 from_init = False
819 Pdir = [P for P in filename.split(os.path.sep) if P.startswith('P')]
820 if Pdir:
821 Pdir = Pdir[-1]
822 group = Pdir.split("_")[0][1:]
823 if not group.isdigit():
824 from_init = True
825 else:
826 from_init = True
827
828 if not from_init:
829 if group in grouped_cross:
830 grouped_cross[group] += self.allcross[i]
831 grouped_error[group] += self.error[i]**2
832 else:
833 grouped_cross[group] = self.allcross[i]
834 grouped_error[group] = self.error[i]**2
835 else:
836 ban = banner_mod.Banner(ff.banner)
837 for line in ban['init'].split('\n'):
838 splitline = line.split()
839 if len(splitline)==4:
840 cross, error, _, group = splitline
841 if int(group) in grouped_cross:
842 grouped_cross[group] += float(cross)
843 grouped_error[group] += float(error)**2
844 else:
845 grouped_cross[group] = float(cross)
846 grouped_error[group] = float(error)**2
847 nb_group = len(grouped_cross)
848
849
850 try:
851 run_card = self.banner.run_card
852 except:
853 run_card = self.banner.charge_card("run_card")
854
855 init_information = run_card.get_banner_init_information()
856 if init_information["idbmup1"] == 0:
857 event = self.next()
858 init_information["idbmup1"]= event[0].pdg
859 if init_information["idbmup2"] == 0:
860 init_information["idbmup2"]= event[1].pdg
861 self.seek(0)
862 if init_information["idbmup2"] == 0:
863 event = self.next()
864 init_information["idbmup2"] = event[1].pdg
865 self.seek(0)
866
867 init_information["nprup"] = nb_group
868
869 if run_card["lhe_version"] < 3:
870 init_information["generator_info"] = ""
871 else:
872 init_information["generator_info"] = "<generator name='MadGraph5_aMC@NLO' version='%s'>please cite 1405.0301 </generator>\n" \
873 % misc.get_pkg_info()['version']
874
875
876 cross_info = "%(cross)e %(error)e %(wgt)e %(id)i"
877 init_information["cross_info"] = []
878 for id in grouped_cross:
879 conv = {"id": int(id), "cross": grouped_cross[id], "error": math.sqrt(grouped_error[id]),
880 "wgt": wgt}
881 init_information["cross_info"].append( cross_info % conv)
882 init_information["cross_info"] = '\n'.join(init_information["cross_info"])
883 init_information['lha_stra'] = -1 * abs(lha_strategy)
884
885 template_init =\
886 """ %(idbmup1)i %(idbmup2)i %(ebmup1)e %(ebmup2)e %(pdfgup1)i %(pdfgup2)i %(pdfsup1)i %(pdfsup2)i %(lha_stra)i %(nprup)i
887 %(cross_info)s
888 %(generator_info)s
889 """
890
891 self.banner["init"] = template_init % init_information
892
893
894
896 """ scan once the file to return
897 - the list of the hightest weight (of size trunc_error*NB_EVENT
898 - the cross-section by type of process
899 - the total number of events in the files
900 In top of that it initialise the information for the next routine
901 to determine how to choose which file to read
902 """
903 self.seek(0)
904 all_wgt = []
905 total_event = 0
906 sum_cross = collections.defaultdict(int)
907 for i,f in enumerate(self.files):
908 nb_event = 0
909
910
911 cross = collections.defaultdict(int)
912 new_wgt =[]
913 for event in f:
914 nb_event += 1
915 total_event += 1
916 event.sample_scale = 1
917 wgt = getwgt(event)
918 cross['all'] += wgt
919 cross['abs'] += abs(wgt)
920 cross[event.ievent] += wgt
921 new_wgt.append(abs(wgt))
922
923 if nb_event % 20000 == 0:
924 new_wgt.sort()
925
926 nb_keep = max(20, int(nb_event*trunc_error*15))
927 new_wgt = new_wgt[-nb_keep:]
928 if nb_event == 0:
929 raise Exception
930
931 self.initial_nb_events[i] = nb_event
932 self.scales[i] = self.across[i]/cross['abs'] if self.across[i] else 1
933
934
935 for key in cross:
936 sum_cross[key] += cross[key]* self.scales[i]
937 all_wgt +=[self.scales[i] * w for w in new_wgt]
938 all_wgt.sort()
939 nb_keep = max(20, int(total_event*trunc_error*10))
940 all_wgt = all_wgt[-nb_keep:]
941
942 self.total_event_in_files = total_event
943
944 all_wgt.sort()
945
946 nb_keep = max(20, int(total_event*trunc_error*10))
947 all_wgt = all_wgt[-nb_keep:]
948 self.seek(0)
949 self._configure = True
950 return all_wgt, sum_cross, total_event
951
958
960
961 return len(self.files)
962
963 - def seek(self, pos):
964 """ """
965
966 if pos !=0:
967 raise Exception
968 for i in range(len(self)):
969 self.curr_nb_events[i] = 0
970 for f in self.files:
971 f.seek(pos)
972
973 - def unweight(self, outputpath, get_wgt, **opts):
974 """unweight the current file according to wgt information wgt.
975 which can either be a fct of the event or a tag in the rwgt list.
976 max_wgt allow to do partial unweighting.
977 trunc_error allow for dynamical partial unweighting
978 event_target reweight for that many event with maximal trunc_error.
979 (stop to write event when target is reached)
980 """
981
982 if isinstance(get_wgt, str):
983 unwgt_name =get_wgt
984 def get_wgt_multi(event):
985 event.parse_reweight()
986 return event.reweight_data[unwgt_name] * event.sample_scale
987 else:
988 unwgt_name = get_wgt.func_name
989 get_wgt_multi = lambda event: get_wgt(event) * event.sample_scale
990
991
992
993 if 'event_target' in opts and opts['event_target']:
994 if 'normalization' in opts:
995 if opts['normalization'] == 'sum':
996 new_wgt = sum(self.across)/opts['event_target']
997 strategy = 3
998 elif opts['normalization'] == 'average':
999 strategy = 4
1000 new_wgt = sum(self.across)
1001 elif opts['normalization'] == 'unit':
1002 strategy =3
1003 new_wgt = 1.
1004 else:
1005 strategy = 4
1006 new_wgt = sum(self.across)
1007 self.define_init_banner(new_wgt, strategy)
1008 self.written_weight = new_wgt
1009 elif 'write_init' in opts and opts['write_init']:
1010 self.define_init_banner(0,0)
1011 del opts['write_init']
1012 return super(MultiEventFile, self).unweight(outputpath, get_wgt_multi, **opts)
1013
1014 - def write(self, path, random=False, banner=None, get_info=False):
1063
1072
1073
1074
1075 -class Event(list):
1076 """Class storing a single event information (list of particles + global information)"""
1077
1078 warning_order = True
1079
1081 """The initialization of an empty Event (or one associate to a text file)"""
1082 list.__init__(self)
1083
1084
1085 self.nexternal = 0
1086 self.ievent = 0
1087 self.wgt = 0
1088 self.aqcd = 0
1089 self.scale = 0
1090 self.aqed = 0
1091 self.aqcd = 0
1092
1093 self.tag = ''
1094 self.eventflag = {}
1095 self.comment = ''
1096 self.reweight_data = {}
1097 self.matched_scale_data = None
1098 self.syscalc_data = {}
1099 if text:
1100 self.parse(text)
1101
1102
1103
1105 """Take the input file and create the structured information"""
1106
1107 status = 'first'
1108 for line in text.split('\n'):
1109 line = line.strip()
1110 if not line:
1111 continue
1112 elif line[0] == '#':
1113 self.comment += '%s\n' % line
1114 continue
1115 elif line.startswith('<event'):
1116 if '=' in line:
1117 found = re.findall(r"""(\w*)=(?:(?:['"])([^'"]*)(?=['"])|(\S*))""",line)
1118
1119
1120 self.eventflag = dict((n, a1) if a1 else (n,a2) for n,a1,a2 in found)
1121
1122 continue
1123
1124 elif 'first' == status:
1125 if '<rwgt>' in line:
1126 status = 'tag'
1127 else:
1128 self.assign_scale_line(line)
1129 status = 'part'
1130 continue
1131 if '<' in line:
1132 status = 'tag'
1133
1134 if 'part' == status:
1135 self.append(Particle(line, event=self))
1136 else:
1137 if '</event>' in line:
1138 line = line.replace('</event>','',1)
1139 self.tag += '%s\n' % line
1140
1141 self.assign_mother()
1142
1144
1145 for i,particle in enumerate(self):
1146 if i < particle.mother1 or i < particle.mother2:
1147 if self.warning_order:
1148 logger.warning("Order of particle in the event did not agree with parent/child order. This might be problematic for some code.")
1149 Event.warning_order = False
1150 self.reorder_mother_child()
1151 return self.assign_mother()
1152
1153 if particle.mother1:
1154 try:
1155 particle.mother1 = self[int(particle.mother1) -1]
1156 except Exception:
1157 logger.warning("WRONG MOTHER INFO %s", self)
1158 particle.mother1 = 0
1159 if particle.mother2:
1160 try:
1161 particle.mother2 = self[int(particle.mother2) -1]
1162 except Exception:
1163 logger.warning("WRONG MOTHER INFO %s", self)
1164 particle.mother2 = 0
1165
1167 """change all the weights by a given ratio"""
1168
1169 self.wgt *= ratio
1170 self.parse_reweight()
1171 for key in self.reweight_data:
1172 self.reweight_data[key] *= ratio
1173 return self.wgt
1174
1176 """check and correct the mother/child position.
1177 only correct one order by call (but this is a recursive call)"""
1178
1179 tomove, position = None, None
1180 for i,particle in enumerate(self):
1181 if i < particle.mother1:
1182
1183 tomove, position = i, particle.mother1-1
1184 break
1185 if i < particle.mother2:
1186 tomove, position = i, particle.mother2-1
1187
1188
1189 if not tomove:
1190 return
1191
1192
1193 particle = self.pop(tomove)
1194 self.insert(int(position), particle)
1195
1196
1197 for i, particle in enumerate(self):
1198 particle.event_id = i
1199
1200 m1, m2 = particle.mother1, particle.mother2
1201 if m1 == tomove +1:
1202 particle.mother1 = position+1
1203 elif tomove < m1 <= position +1:
1204 particle.mother1 -= 1
1205 if m2 == tomove +1:
1206 particle.mother2 = position+1
1207 elif tomove < m2 <= position +1:
1208 particle.mother2 -= 1
1209
1210 return self.reorder_mother_child()
1211
1212
1213
1214
1215
1216
1218 """Parse the re-weight information in order to return a dictionary
1219 {key: value}. If no group is define group should be '' """
1220 if self.reweight_data:
1221 return self.reweight_data
1222 self.reweight_data = {}
1223 self.reweight_order = []
1224 start, stop = self.tag.find('<rwgt>'), self.tag.find('</rwgt>')
1225 if start != -1 != stop :
1226 pattern = re.compile(r'''<\s*wgt id=(?:\'|\")(?P<id>[^\'\"]+)(?:\'|\")\s*>\s*(?P<val>[\ded+-.]*)\s*</wgt>''',re.I)
1227 data = pattern.findall(self.tag[start:stop])
1228 try:
1229 self.reweight_data = dict([(pid, float(value)) for (pid, value) in data
1230 if not self.reweight_order.append(pid)])
1231
1232 except ValueError, error:
1233 raise Exception, 'Event File has unvalid weight. %s' % error
1234 self.tag = self.tag[:start] + self.tag[stop+7:]
1235 return self.reweight_data
1236
1238 """ """
1239 if hasattr(self, 'nloweight'):
1240 return self.nloweight
1241
1242 start, stop = self.tag.find('<mgrwgt>'), self.tag.find('</mgrwgt>')
1243 if start != -1 != stop :
1244
1245 text = self.tag[start+8:stop]
1246 self.nloweight = NLO_PARTIALWEIGHT(text, self, real_type=real_type)
1247 return self.nloweight
1248
1250 """ """
1251 if hasattr(self, 'loweight'):
1252 return self.loweight
1253
1254 start, stop = self.tag.find('<mgrwt>'), self.tag.find('</mgrwt>')
1255
1256 if start != -1 != stop :
1257 text = self.tag[start+8:stop]
1258
1259
1260
1261
1262
1263 self.loweight={}
1264 for line in text.split('\n'):
1265 line = line.replace('<', ' <').replace("'",'"')
1266 if 'rscale' in line:
1267 _, nqcd, scale, _ = line.split()
1268 self.loweight['n_qcd'] = int(nqcd)
1269 self.loweight['ren_scale'] = float(scale)
1270 elif '<pdfrwt beam="1"' in line:
1271 args = line.split()
1272 self.loweight['n_pdfrw1'] = int(args[2])
1273 npdf = self.loweight['n_pdfrw1']
1274 self.loweight['pdf_pdg_code1'] = [int(i) for i in args[3:3+npdf]]
1275 self.loweight['pdf_x1'] = [float(i) for i in args[3+npdf:3+2*npdf]]
1276 self.loweight['pdf_q1'] = [float(i) for i in args[3+2*npdf:3+3*npdf]]
1277 elif '<pdfrwt beam="2"' in line:
1278 args = line.split()
1279 self.loweight['n_pdfrw2'] = int(args[2])
1280 npdf = self.loweight['n_pdfrw2']
1281 self.loweight['pdf_pdg_code2'] = [int(i) for i in args[3:3+npdf]]
1282 self.loweight['pdf_x2'] = [float(i) for i in args[3+npdf:3+2*npdf]]
1283 self.loweight['pdf_q2'] = [float(i) for i in args[3+2*npdf:3+3*npdf]]
1284 elif '<asrwt>' in line:
1285 args = line.replace('>','> ').split()
1286 nalps = int(args[1])
1287 self.loweight['asrwt'] = [float(a) for a in args[2:2+nalps]]
1288
1289 elif 'totfact' in line:
1290 args = line.split()
1291 self.loweight['tot_fact'] = float(args[1])
1292 else:
1293 return None
1294 return self.loweight
1295
1297 """Parse the line containing the starting scale for the shower"""
1298
1299 if self.matched_scale_data is not None:
1300 return self.matched_scale_data
1301
1302 self.matched_scale_data = []
1303
1304
1305 pattern = re.compile("<scales\s|</scales>")
1306 data = re.split(pattern,self.tag)
1307 if len(data) == 1:
1308 return []
1309 else:
1310 tmp = {}
1311 start,content, end = data
1312 self.tag = "%s%s" % (start, end)
1313 pattern = re.compile("pt_clust_(\d*)=\"([\de+-.]*)\"")
1314 for id,value in pattern.findall(content):
1315 tmp[int(id)] = float(value)
1316 for i in range(1, len(self)+1):
1317 if i in tmp:
1318 self.matched_scale_data.append(tmp[i])
1319 else:
1320 self.matched_scale_data.append(-1)
1321 return self.matched_scale_data
1322
1324 """ parse the flag for syscalc between <mgrwt></mgrwt>
1325 <mgrwt>
1326 <rscale> 3 0.26552898E+03</rscale>
1327 <asrwt>0</asrwt>
1328 <pdfrwt beam="1"> 1 21 0.14527945E+00 0.26552898E+03</pdfrwt>
1329 <pdfrwt beam="2"> 1 21 0.15249110E-01 0.26552898E+03</pdfrwt>
1330 <totfact> 0.10344054E+04</totfact>
1331 </mgrwt>
1332 """
1333 if self.syscalc_data:
1334 return self.syscalc_data
1335
1336 pattern = re.compile("<mgrwt>|</mgrwt>")
1337 pattern2 = re.compile("<(?P<tag>[\w]*)(?:\s*(\w*)=[\"'](.*)[\"']\s*|\s*)>(.*)</(?P=tag)>")
1338 data = re.split(pattern,self.tag)
1339 if len(data) == 1:
1340 return []
1341 else:
1342 tmp = {}
1343 start,content, end = data
1344 self.tag = "%s%s" % (start, end)
1345 for tag, key, keyval, tagval in pattern2.findall(content):
1346 if key:
1347 self.syscalc_data[(tag, key, keyval)] = tagval
1348 else:
1349 self.syscalc_data[tag] = tagval
1350 return self.syscalc_data
1351
1352
1353 - def add_decay_to_particle(self, position, decay_event):
1354 """define the decay of the particle id by the event pass in argument"""
1355
1356 this_particle = self[position]
1357
1358 this_particle.status = 2
1359 this_particle.helicity = 0
1360
1361
1362 decay_particle = decay_event[0]
1363 this_4mom = FourMomentum(this_particle)
1364 nb_part = len(self)
1365
1366 thres = decay_particle.E*1e-10
1367 assert max(decay_particle.px, decay_particle.py, decay_particle.pz) < thres,\
1368 "not on rest particle %s %s %s %s" % (decay_particle.E, decay_particle.px,decay_particle.py,decay_particle.pz)
1369
1370 self.nexternal += decay_event.nexternal -1
1371 old_scales = list(self.parse_matching_scale())
1372 if old_scales:
1373 jet_position = sum(1 for i in range(position) if self[i].status==1)
1374 initial_pos = sum(1 for i in range(position) if self[i].status==-1)
1375 self.matched_scale_data.pop(initial_pos+jet_position)
1376
1377
1378 for particle in decay_event[1:]:
1379
1380 new_particle = Particle(particle, self)
1381 new_particle.event_id = len(self)
1382 self.append(new_particle)
1383 if old_scales:
1384 self.matched_scale_data.append(old_scales[initial_pos+jet_position])
1385
1386 new_momentum = this_4mom.boost(FourMomentum(new_particle))
1387 new_particle.set_momentum(new_momentum)
1388
1389 for tag in ['mother1', 'mother2']:
1390 mother = getattr(particle, tag)
1391 if isinstance(mother, Particle):
1392 mother_id = getattr(particle, tag).event_id
1393 if mother_id == 0:
1394 setattr(new_particle, tag, this_particle)
1395 else:
1396 try:
1397 setattr(new_particle, tag, self[nb_part + mother_id -1])
1398 except Exception, error:
1399 print error
1400 misc.sprint( self)
1401 misc.sprint(nb_part + mother_id -1)
1402 misc.sprint(tag)
1403 misc.sprint(position, decay_event)
1404 misc.sprint(particle)
1405 misc.sprint(len(self), nb_part + mother_id -1)
1406 raise
1407 elif tag == "mother2" and isinstance(particle.mother1, Particle):
1408 new_particle.mother2 = this_particle
1409 else:
1410 raise Exception, "Something weird happens. Please report it for investigation"
1411
1412
1413 max_color=501
1414 for particle in self[:nb_part]:
1415 max_color=max(max_color, particle.color1, particle.color2)
1416
1417
1418 color_mapping = {}
1419 color_mapping[decay_particle.color1] = this_particle.color1
1420 color_mapping[decay_particle.color2] = this_particle.color2
1421 for particle in self[nb_part:]:
1422 if particle.color1:
1423 if particle.color1 not in color_mapping:
1424 max_color +=1
1425 color_mapping[particle.color1] = max_color
1426 particle.color1 = max_color
1427 else:
1428 particle.color1 = color_mapping[particle.color1]
1429 if particle.color2:
1430 if particle.color2 not in color_mapping:
1431 max_color +=1
1432 color_mapping[particle.color2] = max_color
1433 particle.color2 = max_color
1434 else:
1435 particle.color2 = color_mapping[particle.color2]
1436
1438 """use auto-recursion"""
1439
1440 pdg_to_decay = dict(pdg_to_decay)
1441
1442 for i,particle in enumerate(self):
1443 if particle.status != 1:
1444 continue
1445 if particle.pdg in pdg_to_decay and pdg_to_decay[particle.pdg]:
1446 one_decay = pdg_to_decay[particle.pdg].pop()
1447 self.add_decay_to_particle(i, one_decay)
1448 return self.add_decays(pdg_to_decay)
1449 return self
1450
1451
1452
1454
1455 to_remove = []
1456 if event_id is not None:
1457 to_remove.append(self[event_id])
1458
1459 if pdg_code:
1460 for particle in self:
1461 if particle.pid == pdg_code:
1462 to_remove.append(particle)
1463
1464 new_event = Event()
1465
1466 for tag in ['nexternal', 'ievent', 'wgt', 'aqcd', 'scale', 'aqed','tag','comment']:
1467 setattr(new_event, tag, getattr(self, tag))
1468
1469 for particle in self:
1470 if isinstance(particle.mother1, Particle) and particle.mother1 in to_remove:
1471 to_remove.append(particle)
1472 if particle.status == 1:
1473 new_event.nexternal -= 1
1474 continue
1475 elif isinstance(particle.mother2, Particle) and particle.mother2 in to_remove:
1476 to_remove.append(particle)
1477 if particle.status == 1:
1478 new_event.nexternal -= 1
1479 continue
1480 else:
1481 new_event.append(Particle(particle))
1482
1483
1484
1485 for pos, particle in enumerate(new_event):
1486 particle.event_id = pos
1487 if particle in to_remove:
1488 particle.status = 1
1489 return new_event
1490
1491 - def get_decay(self, pdg_code=0, event_id=None):
1492
1493 to_start = []
1494 if event_id is not None:
1495 to_start.append(self[event_id])
1496
1497 elif pdg_code:
1498 for particle in self:
1499 if particle.pid == pdg_code:
1500 to_start.append(particle)
1501 break
1502
1503 new_event = Event()
1504
1505 for tag in ['ievent', 'wgt', 'aqcd', 'scale', 'aqed','tag','comment']:
1506 setattr(new_event, tag, getattr(self, tag))
1507
1508
1509 old2new = {}
1510 new_decay_part = Particle(to_start[0])
1511 new_decay_part.mother1 = None
1512 new_decay_part.mother2 = None
1513 new_decay_part.status = -1
1514 old2new[new_decay_part.event_id] = len(old2new)
1515 new_event.append(new_decay_part)
1516
1517
1518
1519 for particle in self:
1520 if isinstance(particle.mother1, Particle) and particle.mother1.event_id in old2new\
1521 or isinstance(particle.mother2, Particle) and particle.mother2.event_id in old2new:
1522 old2new[particle.event_id] = len(old2new)
1523 new_event.append(Particle(particle))
1524
1525
1526
1527 nexternal = 0
1528 for pos, particle in enumerate(new_event):
1529 particle.event_id = pos
1530 if particle.mother1:
1531 particle.mother1 = new_event[old2new[particle.mother1.event_id]]
1532 if particle.mother2:
1533 particle.mother2 = new_event[old2new[particle.mother2.event_id]]
1534 if particle.status in [-1,1]:
1535 nexternal +=1
1536 new_event.nexternal = nexternal
1537
1538 return new_event
1539
1540
1542 """check various property of the events"""
1543
1544
1545 E, px, py, pz = 0,0,0,0
1546 absE, abspx, abspy, abspz = 0,0,0,0
1547 for particle in self:
1548 coeff = 1
1549 if particle.status == -1:
1550 coeff = -1
1551 elif particle.status != 1:
1552 continue
1553 E += coeff * particle.E
1554 absE += abs(particle.E)
1555 px += coeff * particle.px
1556 py += coeff * particle.py
1557 pz += coeff * particle.pz
1558 abspx += abs(particle.px)
1559 abspy += abs(particle.py)
1560 abspz += abs(particle.pz)
1561
1562 threshold = 5e-7
1563 if E/absE > threshold:
1564 logger.critical(self)
1565 raise Exception, "Do not conserve Energy %s, %s" % (E/absE, E)
1566 if px/abspx > threshold:
1567 logger.critical(self)
1568 raise Exception, "Do not conserve Px %s, %s" % (px/abspx, px)
1569 if py/abspy > threshold:
1570 logger.critical(self)
1571 raise Exception, "Do not conserve Py %s, %s" % (py/abspy, py)
1572 if pz/abspz > threshold:
1573 logger.critical(self)
1574 raise Exception, "Do not conserve Pz %s, %s" % (pz/abspz, pz)
1575
1576
1577 self.check_color_structure()
1578
1580 """read the line corresponding to global event line
1581 format of the line is:
1582 Nexternal IEVENT WEIGHT SCALE AEW AS
1583 """
1584 inputs = line.split()
1585 assert len(inputs) == 6
1586 self.nexternal=int(inputs[0])
1587 self.ievent=int(inputs[1])
1588 self.wgt=float(inputs[2])
1589 self.scale=float(inputs[3])
1590 self.aqed=float(inputs[4])
1591 self.aqcd=float(inputs[5])
1592
1594 """Return the unique tag identifying the SubProcesses for the generation.
1595 Usefull for program like MadSpin and Reweight module."""
1596
1597 initial, final, order = [], [], [[], []]
1598 for particle in self:
1599 if particle.status == -1:
1600 initial.append(particle.pid)
1601 order[0].append(particle.pid)
1602 elif particle.status == 1:
1603 final.append(particle.pid)
1604 order[1].append(particle.pid)
1605 initial.sort(), final.sort()
1606 tag = (tuple(initial), tuple(final))
1607 return tag, order
1608
1610 """return a list with the helicities in the order asked for"""
1611
1612
1613 order = [list(get_order[0]), list(get_order[1])]
1614 out = [9] *(len(order[0])+len(order[1]))
1615 for i, part in enumerate(self):
1616 if part.status == 1:
1617 try:
1618 ind = order[1].index(part.pid)
1619 except ValueError, error:
1620 if not allow_reversed:
1621 raise error
1622 else:
1623 order = [[-i for i in get_order[0]],[-i for i in get_order[1]]]
1624 try:
1625 return self.get_helicity(order, False)
1626 except ValueError:
1627 raise error
1628 position = len(order[0]) + ind
1629 order[1][ind] = 0
1630 elif part.status == -1:
1631 try:
1632 ind = order[0].index(part.pid)
1633 except ValueError, error:
1634 if not allow_reversed:
1635 raise error
1636 else:
1637 order = [[-i for i in get_order[0]],[-i for i in get_order[1]]]
1638 try:
1639 return self.get_helicity(order, False)
1640 except ValueError:
1641 raise error
1642
1643 position = ind
1644 order[0][ind] = 0
1645 else:
1646 continue
1647 out[position] = int(part.helicity)
1648 return out
1649
1650
1652 """check the validity of the color structure"""
1653
1654
1655 color_index = collections.defaultdict(int)
1656 for particle in self:
1657 if particle.status in [-1,1]:
1658 if particle.color1:
1659 color_index[particle.color1] +=1
1660 if -7 < particle.pdg < 0:
1661 raise Exception, "anti-quark with color tag"
1662 if particle.color2:
1663 color_index[particle.color2] +=1
1664 if 7 > particle.pdg > 0:
1665 raise Exception, "quark with anti-color tag"
1666
1667
1668 for key,value in color_index.items():
1669 if value > 2:
1670 print self
1671 print key, value
1672 raise Exception, 'Wrong color_flow'
1673
1674
1675
1676 check = []
1677 popup_index = []
1678 for particle in self:
1679 mothers = []
1680 childs = []
1681 if particle.mother1:
1682 mothers.append(particle.mother1)
1683 if particle.mother2 and particle.mother2 is not particle.mother1:
1684 mothers.append(particle.mother2)
1685 if not mothers:
1686 continue
1687 if (particle.mother1.event_id, particle.mother2.event_id) in check:
1688 continue
1689 check.append((particle.mother1.event_id, particle.mother2.event_id))
1690
1691 childs = [p for p in self if p.mother1 is particle.mother1 and \
1692 p.mother2 is particle.mother2]
1693
1694 mcolors = []
1695 manticolors = []
1696 for m in mothers:
1697 if m.color1:
1698 if m.color1 in manticolors:
1699 manticolors.remove(m.color1)
1700 else:
1701 mcolors.append(m.color1)
1702 if m.color2:
1703 if m.color2 in mcolors:
1704 mcolors.remove(m.color2)
1705 else:
1706 manticolors.append(m.color2)
1707 ccolors = []
1708 canticolors = []
1709 for m in childs:
1710 if m.color1:
1711 if m.color1 in canticolors:
1712 canticolors.remove(m.color1)
1713 else:
1714 ccolors.append(m.color1)
1715 if m.color2:
1716 if m.color2 in ccolors:
1717 ccolors.remove(m.color2)
1718 else:
1719 canticolors.append(m.color2)
1720 for index in mcolors[:]:
1721 if index in ccolors:
1722 mcolors.remove(index)
1723 ccolors.remove(index)
1724 for index in manticolors[:]:
1725 if index in canticolors:
1726 manticolors.remove(index)
1727 canticolors.remove(index)
1728
1729 if mcolors != []:
1730
1731 if len(canticolors) + len(mcolors) != 3:
1732 logger.critical(str(self))
1733 raise Exception, "Wrong color flow for %s -> %s" ([m.pid for m in mothers], [c.pid for c in childs])
1734 else:
1735 popup_index += canticolors
1736 elif manticolors != []:
1737
1738 if len(ccolors) + len(manticolors) != 3:
1739 logger.critical(str(self))
1740 raise Exception, "Wrong color flow for %s -> %s" ([m.pid for m in mothers], [c.pid for c in childs])
1741 else:
1742 popup_index += ccolors
1743
1744
1745 if len(popup_index) != len(set(popup_index)):
1746 logger.critical(self)
1747 raise Exception, "Wrong color flow: identical poping-up index, %s" % (popup_index)
1748
1750 """two event are the same if they have the same momentum. other info are ignored"""
1751
1752 if other is None:
1753 return False
1754
1755 for i,p in enumerate(self):
1756 if p.E != other[i].E:
1757 return False
1758 elif p.pz != other[i].pz:
1759 return False
1760 elif p.px != other[i].px:
1761 return False
1762 elif p.py != other[i].py:
1763 return False
1764 return True
1765
1766
1768 """return a correctly formatted LHE event"""
1769
1770 out="""<event%(event_flag)s>
1771 %(scale)s
1772 %(particles)s
1773 %(comments)s
1774 %(tag)s
1775 %(reweight)s
1776 </event>
1777 """
1778 if event_id not in ['', None]:
1779 self.eventflag['event'] = str(event_id)
1780
1781 if self.eventflag:
1782 event_flag = ' %s' % ' '.join('%s="%s"' % (k,v) for (k,v) in self.eventflag.items())
1783 else:
1784 event_flag = ''
1785
1786 if self.nexternal:
1787 scale_str = "%2d %6d %+13.7e %14.8e %14.8e %14.8e" % \
1788 (self.nexternal,self.ievent,self.wgt,self.scale,self.aqed,self.aqcd)
1789 else:
1790 scale_str = ''
1791
1792 if self.reweight_data:
1793
1794 if set(self.reweight_data.keys()) != set(self.reweight_order):
1795 self.reweight_order += [k for k in self.reweight_data.keys() \
1796 if k not in self.reweight_order]
1797
1798 reweight_str = '<rwgt>\n%s\n</rwgt>' % '\n'.join(
1799 '<wgt id=\'%s\'> %+13.7e </wgt>' % (i, float(self.reweight_data[i]))
1800 for i in self.reweight_order)
1801 else:
1802 reweight_str = ''
1803
1804 tag_str = self.tag
1805 if self.matched_scale_data:
1806 tmp_scale = ' '.join(['pt_clust_%i=\"%s\"' % (i+1,v)
1807 for i,v in enumerate(self.matched_scale_data)
1808 if v!=-1])
1809 if tmp_scale:
1810 tag_str = "<scales %s></scales>%s" % (tmp_scale, self.tag)
1811
1812 if self.syscalc_data:
1813 keys= ['rscale', 'asrwt', ('pdfrwt', 'beam', '1'), ('pdfrwt', 'beam', '2'),
1814 'matchscale', 'totfact']
1815 sys_str = "<mgrwt>\n"
1816 template = """<%(key)s%(opts)s>%(values)s</%(key)s>\n"""
1817 for k in keys:
1818 if k not in self.syscalc_data:
1819 continue
1820 replace = {}
1821 replace['values'] = self.syscalc_data[k]
1822 if isinstance(k, str):
1823 replace['key'] = k
1824 replace['opts'] = ''
1825 else:
1826 replace['key'] = k[0]
1827 replace['opts'] = ' %s=\"%s\"' % (k[1],k[2])
1828 sys_str += template % replace
1829 sys_str += "</mgrwt>\n"
1830 reweight_str = sys_str + reweight_str
1831
1832 out = out % {'event_flag': event_flag,
1833 'scale': scale_str,
1834 'particles': '\n'.join([str(p) for p in self]),
1835 'tag': tag_str,
1836 'comments': self.comment,
1837 'reweight': reweight_str}
1838
1839 return re.sub('[\n]+', '\n', out)
1840
1841 - def get_momenta(self, get_order, allow_reversed=True):
1842 """return the momenta vector in the order asked for"""
1843
1844
1845 order = [list(get_order[0]), list(get_order[1])]
1846 out = [''] *(len(order[0])+len(order[1]))
1847 for i, part in enumerate(self):
1848 if part.status == 1:
1849 try:
1850 ind = order[1].index(part.pid)
1851 except ValueError, error:
1852 if not allow_reversed:
1853 raise error
1854 else:
1855 order = [[-i for i in get_order[0]],[-i for i in get_order[1]]]
1856 try:
1857 return self.get_momenta_str(order, False)
1858 except ValueError:
1859 raise error
1860 position = len(order[0]) + ind
1861 order[1][ind] = 0
1862 elif part.status == -1:
1863 try:
1864 ind = order[0].index(part.pid)
1865 except ValueError, error:
1866 if not allow_reversed:
1867 raise error
1868 else:
1869 order = [[-i for i in get_order[0]],[-i for i in get_order[1]]]
1870 try:
1871 return self.get_momenta_str(order, False)
1872 except ValueError:
1873 raise error
1874
1875 position = ind
1876 order[0][ind] = 0
1877 else:
1878 continue
1879
1880 out[position] = (part.E, part.px, part.py, part.pz)
1881
1882 return out
1883
1884
1885
1887
1888 scale = 0
1889 for particle in self:
1890 if particle.status != 1:
1891 continue
1892 p=FourMomentum(particle)
1893 scale += math.sqrt(p.mass_sqr + p.pt**2)
1894
1895 return prefactor * scale
1896
1897
1899
1900 scale = 0
1901 for particle in self:
1902 if particle.status != 1:
1903 continue
1904 p = FourMomentum(particle)
1905 pt = p.pt
1906 if (pt>0):
1907 scale += p.E*pt/math.sqrt(pt**2+p.pz**2)
1908
1909 return prefactor * scale
1910
1912
1913 scale = 0
1914 init = []
1915 for particle in self:
1916 if particle.status == -1:
1917 init.append(FourMomentum(particle))
1918 if len(init) == 1:
1919 return init[0].mass
1920 elif len(init)==2:
1921 return math.sqrt((init[0]+init[1])**2)
1922
1923
1924
1925
1927 """return the momenta str in the order asked for"""
1928
1929 out = self.get_momenta(get_order, allow_reversed)
1930
1931 format = '%.12f'
1932 format_line = ' '.join([format]*4) + ' \n'
1933 out = [format_line % one for one in out]
1934 out = ''.join(out).replace('e','d')
1935 return out
1936
1938 """A class to allow to read both gzip and not gzip file.
1939 containing only weight from pythia --generated by SysCalc"""
1940
1941 - def __new__(self, path, mode='r', *args, **opt):
1942 if path.endswith(".gz"):
1943 try:
1944 return gzip.GzipFile.__new__(WeightFileGzip, path, mode, *args, **opt)
1945 except IOError, error:
1946 raise
1947 except Exception, error:
1948 if mode == 'r':
1949 misc.gunzip(path)
1950 return file.__new__(WeightFileNoGzip, path[:-3], mode, *args, **opt)
1951 else:
1952 return file.__new__(WeightFileNoGzip, path, mode, *args, **opt)
1953
1954
1955 - def __init__(self, path, mode='r', *args, **opt):
1956 """open file and read the banner [if in read mode]"""
1957
1958 super(EventFile, self).__init__(path, mode, *args, **opt)
1959 self.banner = ''
1960 if mode == 'r':
1961 line = ''
1962 while '</header>' not in line.lower():
1963 try:
1964 line = super(EventFile, self).next()
1965 except StopIteration:
1966 self.seek(0)
1967 self.banner = ''
1968 break
1969 if "<event" in line.lower():
1970 self.seek(0)
1971 self.banner = ''
1972 break
1973
1974 self.banner += line
1975
1979
1982
1985 """a convenient object for 4-momenta operation"""
1986
1987 - def __init__(self, obj=0, px=0, py=0, pz=0, E=0):
1988 """initialize the four momenta"""
1989
1990 if obj is 0 and E:
1991 obj = E
1992
1993 if isinstance(obj, (FourMomentum, Particle)):
1994 px = obj.px
1995 py = obj.py
1996 pz = obj.pz
1997 E = obj.E
1998 elif isinstance(obj, (list, tuple)):
1999 assert len(obj) ==4
2000 E = obj[0]
2001 px = obj[1]
2002 py = obj[2]
2003 pz = obj[3]
2004 elif isinstance(obj, str):
2005 obj = [float(i) for i in obj.split()]
2006 assert len(obj) ==4
2007 E = obj[0]
2008 px = obj[1]
2009 py = obj[2]
2010 pz = obj[3]
2011 else:
2012 E =obj
2013
2014
2015 self.E = float(E)
2016 self.px = float(px)
2017 self.py = float(py)
2018 self.pz = float(pz)
2019
2020 @property
2022 """return the mass"""
2023 return math.sqrt(self.E**2 - self.px**2 - self.py**2 - self.pz**2)
2024
2025 @property
2027 """return the mass square"""
2028 return self.E**2 - self.px**2 - self.py**2 - self.pz**2
2029
2030 @property
2032 return math.sqrt(max(0, self.pt2()))
2033
2034 @property
2036 norm = math.sqrt(self.px**2 + self.py**2+self.pz**2)
2037 return 0.5* math.log((norm - self.pz) / (norm + self.pz))
2038
2039 @property
2041 return 0.5* math.log((self.E +self.pz) / (self.E - self.pz))
2042
2043
2044
2046 """ return the pt square """
2047
2048 return self.px**2 + self.py**2
2049
2051
2052 assert isinstance(obj, FourMomentum)
2053 new = FourMomentum(self.E+obj.E,
2054 self.px + obj.px,
2055 self.py + obj.py,
2056 self.pz + obj.pz)
2057 return new
2058
2060 """update the object with the sum"""
2061 self.E += obj.E
2062 self.px += obj.px
2063 self.py += obj.py
2064 self.pz += obj.pz
2065 return self
2066
2068
2069 assert isinstance(obj, FourMomentum)
2070 new = FourMomentum(self.E-obj.E,
2071 self.px - obj.px,
2072 self.py - obj.py,
2073 self.pz - obj.pz)
2074 return new
2075
2077 """update the object with the sum"""
2078 self.E -= obj.E
2079 self.px -= obj.px
2080 self.py -= obj.py
2081 self.pz -= obj.pz
2082 return self
2083
2085 if isinstance(obj, FourMomentum):
2086 return self.E*obj.E - self.px *obj.px - self.py * obj.py - self.pz * obj.pz
2087 elif isinstance(obj, (float, int)):
2088 return FourMomentum(obj*self.E,obj*self.px,obj*self.py,obj*self.pz )
2089 else:
2090 raise NotImplemented
2091 __rmul__ = __mul__
2092
2094 assert power in [1,2]
2095
2096 if power == 1:
2097 return FourMomentum(self)
2098 elif power == 2:
2099 return self.mass_sqr
2100
2102 return 'FourMomentum(%s,%s,%s,%s)' % (self.E, self.px, self.py,self.pz)
2103
2105 return (self.E, self.px, self.py,self.pz)
2106
2108 """mom 4-momenta is suppose to be given in the rest frame of this 4-momenta.
2109 the output is the 4-momenta in the frame of this 4-momenta
2110 function copied from HELAS routine."""
2111
2112
2113 pt = self.px**2 + self.py**2 + self.pz**2
2114 if pt:
2115 s3product = self.px * mom.px + self.py * mom.py + self.pz * mom.pz
2116 mass = self.mass
2117 lf = (mom.E + (self.E - mass) * s3product / pt ) / mass
2118 return FourMomentum(E=(self.E*mom.E+s3product)/mass,
2119 px=mom.px + self.px * lf,
2120 py=mom.py + self.py * lf,
2121 pz=mom.pz + self.pz * lf)
2122 else:
2123 return FourMomentum(mom)
2124
2125 - def zboost(self, pboost=None, E=0, pz=0):
2126 """Both momenta should be in the same frame.
2127 The boost perform correspond to the boost required to set pboost at
2128 rest (only z boost applied).
2129 """
2130 if isinstance(pboost, FourMomentum):
2131 E = pboost.E
2132 pz = pboost.pz
2133
2134
2135 gamma = E / math.sqrt(E**2-pz**2)
2136 gammabeta = pz / math.sqrt(E**2-pz**2)
2137
2138 out = FourMomentum([gamma*self.E - gammabeta*self.pz,
2139 self.px,
2140 self.py,
2141 gamma*self.pz - gammabeta*self.E])
2142
2143 if abs(out.pz) < 1e-6 * out.E:
2144 out.pz = 0
2145 return out
2146
2148 """apply the boost transformation such that pboost is at rest in the new frame.
2149 First apply a rotation to allign the pboost to the z axis and then use
2150 zboost routine (see above)
2151 """
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161 p = math.sqrt( pboost.px**2 + pboost.py**2+ pboost.pz**2)
2162 cosF = pboost.pz / p
2163 sinF = math.sqrt(1-cosF**2)
2164 sinT = pboost.py/p/sinF
2165 cosT = pboost.px/p/sinF
2166
2167 out=FourMomentum([self.E,
2168 self.px*cosT*cosF + self.py*sinT*cosF-self.pz*sinF,
2169 -self.px*sinT+ self.py*cosT,
2170 self.px*cosT*sinF + self.py*sinT*sinF + self.pz*cosF
2171 ])
2172 out = out.zboost(E=pboost.E,pz=p)
2173 return out
2174
2179
2180 - def __init__(self, input, real_type=(1,11)):
2181 """ """
2182
2183 self.real_type = real_type
2184 if isinstance(input, str):
2185 self.parse(input)
2186
2188
2189 out = """ pwgt: %(pwgt)s
2190 born, real : %(born)s %(real)s
2191 pdgs : %(pdgs)s
2192 bjks : %(bjks)s
2193 scales**2, gs: %(scales2)s %(gs)s
2194 born/real related : %(born_related)s %(real_related)s
2195 type / nfks : %(type)s %(nfks)s
2196 to merge : %(to_merge_pdg)s in %(merge_new_pdg)s
2197 ref_wgt : %(ref_wgt)s""" % self.__dict__
2198 return out
2199
2200
2202 """parse the line and create the related object"""
2203
2204
2205
2206 data = text.split()
2207
2208
2209
2210
2211 self.pwgt = [float(f) for f in data[:3]]
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230 self.born = float(data[3])
2231 self.real = float(data[4])
2232
2233
2234 self.nexternal = int(data[5])
2235
2236
2237 self.pdgs = [int(i) for i in data[6:6+self.nexternal]]
2238 flag = 6+self.nexternal
2239
2240
2241 self.qcdpower = int(data[flag])
2242
2243
2244 self.bjks = [float(f) for f in data[flag+1:flag+3]]
2245
2246
2247 self.scales2 = [float(f) for f in data[flag+3:flag+6]]
2248
2249
2250 self.gs = float(data[flag+6])
2251
2252
2253
2254
2255
2256
2257
2258 self.born_related = int(data[flag+7])
2259 self.real_related = int(data[flag+8])
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283 self.type = int(data[flag+9])
2284
2285
2286
2287
2288 self.nfks = int(data[flag+10])
2289
2290
2291
2292
2293
2294
2295
2296 self.to_merge_pdg = [int (f) for f in data[flag+11:flag+13]]
2297
2298
2299 self.merge_new_pdg = int(data[flag+13])
2300
2301
2302
2303
2304
2305 self.ref_wgt = float(data[flag+14])
2306
2307
2308 if self.type in self.real_type:
2309 self.momenta_config = self.real_related
2310 else:
2311 self.momenta_config = self.born_related
2312
2315
2317
2318 - def __init__(self, momenta, wgts, event, real_type=(1,11)):
2319 list.__init__(self, momenta)
2320
2321 assert self
2322 self.wgts = wgts
2323 self.pdgs = list(wgts[0].pdgs)
2324 self.event = event
2325 self.real_type = real_type
2326
2327 if wgts[0].momenta_config == wgts[0].born_related:
2328
2329 ind1, ind2 = [ind-1 for ind in wgts[0].to_merge_pdg]
2330 if ind1> ind2:
2331 ind1, ind2 = ind2, ind1
2332 if ind1 >= sum(1 for p in event if p.status==-1):
2333 new_p = self[ind1] + self[ind2]
2334 else:
2335 new_p = self[ind1] - self[ind2]
2336 self.pop(ind1)
2337 self.insert(ind1, new_p)
2338 self.pop(ind2)
2339 self.pdgs.pop(ind1)
2340 self.pdgs.insert(ind1, wgts[0].merge_new_pdg )
2341 self.pdgs.pop(ind2)
2342
2343 elif any(w.type in self.real_type for w in wgts):
2344 if any(w.type not in self.real_type for w in wgts):
2345 raise Exception
2346
2347 ind1, ind2 = [ind-1 for ind in wgts[0].to_merge_pdg]
2348 if ind1> ind2:
2349 ind1, ind2 = ind2, ind1
2350 if ind1 >= sum(1 for p in event if p.status==-1):
2351 new_p = self[ind1] + self[ind2]
2352 else:
2353 new_p = self[ind1] - self[ind2]
2354
2355 if __debug__:
2356 ptot = FourMomentum()
2357 for i in xrange(len(self)):
2358 if i <2:
2359 ptot += self[i]
2360 else:
2361 ptot -= self[i]
2362 if ptot.mass_sqr > 1e-16:
2363 misc.sprint(ptot, ptot.mass_sqr)
2364
2365 inv_mass = new_p.mass_sqr
2366 shat = (self[0]+self[1]).mass_sqr
2367 if (abs(inv_mass)/shat < 1e-6):
2368
2369 self.pop(ind1)
2370 self.insert(ind1, new_p)
2371 self.pop(ind2)
2372 self.pdgs.pop(ind1)
2373 self.pdgs.insert(ind1, wgts[0].merge_new_pdg )
2374 self.pdgs.pop(ind2)
2375
2376
2377 if __debug__:
2378 ptot = FourMomentum()
2379 for i in xrange(len(self)):
2380 if i <2:
2381 ptot += self[i]
2382 else:
2383 ptot -= self[i]
2384 if ptot.mass_sqr > 1e-16:
2385 misc.sprint(ptot, ptot.mass_sqr)
2386
2387 else:
2388 raise Exception
2389
2392
2394 """ return the tag and order for this basic event"""
2395 (initial, _), _ = self.event.get_tag_and_order()
2396 order = self.get_pdg_code()
2397
2398
2399 initial, out = order[:len(initial)], order[len(initial):]
2400 initial.sort()
2401 out.sort()
2402 return (tuple(initial), tuple(out)), order
2403
2404 - def get_momenta(self, get_order, allow_reversed=True):
2405 """return the momenta vector in the order asked for"""
2406
2407
2408 order = [list(get_order[0]), list(get_order[1])]
2409 out = [''] *(len(order[0])+len(order[1]))
2410 pdgs = self.get_pdg_code()
2411 for pos, part in enumerate(self):
2412 if pos < len(get_order[0]):
2413 try:
2414 ind = order[0].index(pdgs[pos])
2415 except ValueError, error:
2416 if not allow_reversed:
2417 raise error
2418 else:
2419 order = [[-i for i in get_order[0]],[-i for i in get_order[1]]]
2420 try:
2421 return self.get_momenta(order, False)
2422 except ValueError:
2423 raise error
2424
2425
2426 position = ind
2427 order[0][ind] = 0
2428 else:
2429 try:
2430 ind = order[1].index(pdgs[pos])
2431 except ValueError, error:
2432 if not allow_reversed:
2433 raise error
2434 else:
2435 order = [[-i for i in get_order[0]],[-i for i in get_order[1]]]
2436 try:
2437 return self.get_momenta(order, False)
2438 except ValueError:
2439 raise error
2440 position = len(order[0]) + ind
2441 order[1][ind] = 0
2442
2443 out[position] = (part.E, part.px, part.py, part.pz)
2444
2445 return out
2446
2447
2449 return [9] * len(self)
2450
2451 @property
2453 return self.event.aqcd
2454
2456
2457 scale = 0
2458 for particle in self:
2459 p = particle
2460 scale += math.sqrt(max(0, p.mass_sqr + p.pt**2))
2461
2462 return prefactor * scale
2463
2465
2466 scale = 0
2467 for particle in self:
2468 p = particle
2469 pt = p.pt
2470 if (pt>0):
2471 scale += p.E*pt/math.sqrt(pt**2+p.pz**2)
2472
2473 return prefactor * scale
2474
2475
2477
2478 scale = 0
2479 nb_init = 0
2480 for particle in event:
2481 if particle.status == -1:
2482 nb_init+=1
2483 if nb_init == 1:
2484 return self[0].mass
2485 elif nb_init==2:
2486 return math.sqrt((self[0]+self[1])**2)
2487
2488
2489
2490
2491 - def __init__(self, input, event, real_type=(1,11)):
2492
2493 self.real_type = real_type
2494 self.event = event
2495 if isinstance(input, str):
2496 self.parse(input)
2497
2498
2500 """create the object from the string information (see example below)"""
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521 text = text.lower().replace('d','e')
2522 all_line = text.split('\n')
2523
2524 first_line =''
2525 while not first_line.strip():
2526 first_line = all_line.pop(0)
2527
2528 wgt, nb_wgt, nb_event, _ = first_line.split()
2529 nb_wgt, nb_event = int(nb_wgt), int(nb_event)
2530
2531 momenta = []
2532 wgts = []
2533 for line in all_line:
2534 data = line.split()
2535 if len(data) == 4:
2536 p = FourMomentum(data)
2537 momenta.append(p)
2538 elif len(data)>0:
2539 wgt = OneNLOWeight(line, real_type=self.real_type)
2540 wgts.append(wgt)
2541
2542 assert len(wgts) == int(nb_wgt)
2543
2544 get_weights_for_momenta = {}
2545 size_momenta = 0
2546 for wgt in wgts:
2547 if wgt.momenta_config in get_weights_for_momenta:
2548 get_weights_for_momenta[wgt.momenta_config].append(wgt)
2549 else:
2550 if size_momenta == 0: size_momenta = wgt.nexternal
2551 assert size_momenta == wgt.nexternal
2552 get_weights_for_momenta[wgt.momenta_config] = [wgt]
2553
2554 assert sum(len(c) for c in get_weights_for_momenta.values()) == int(nb_wgt), "%s != %s" % (sum(len(c) for c in get_weights_for_momenta.values()), nb_wgt)
2555
2556
2557
2558 self.cevents = []
2559 for key in range(1, nb_event+1):
2560 if key in get_weights_for_momenta:
2561 wgt = get_weights_for_momenta[key]
2562 evt = self.BasicEvent(momenta[:size_momenta], get_weights_for_momenta[key], self.event, self.real_type)
2563 self.cevents.append(evt)
2564 momenta = momenta[size_momenta:]
2565
2566 nb_wgt_check = 0
2567 for cevt in self.cevents:
2568 nb_wgt_check += len(cevt.wgts)
2569 assert nb_wgt_check == int(nb_wgt)
2570
2571
2572
2573 if '__main__' == __name__:
2574
2575
2576 if False:
2577 lhe = EventFile('unweighted_events.lhe.gz')
2578 output = open('output_events.lhe', 'w')
2579
2580 output.write(lhe.banner)
2581
2582 for event in lhe:
2583 for particle in event:
2584
2585 particle.mass = 0
2586 particle.vtim = 2
2587
2588
2589 output.write(str(event))
2590 output.write('</LesHouchesEvent>\n')
2591
2592
2593 if False:
2594 lhe = EventFile('unweighted_events.lhe.gz')
2595 import matplotlib.pyplot as plt
2596 import matplotlib.gridspec as gridspec
2597 nbins = 100
2598
2599 nb_pass = 0
2600 data = []
2601 for event in lhe:
2602 etaabs = 0
2603 etafinal = 0
2604 for particle in event:
2605 if particle.status==1:
2606 p = FourMomentum(particle)
2607 eta = p.pseudorapidity
2608 if abs(eta) > etaabs:
2609 etafinal = eta
2610 etaabs = abs(eta)
2611 if etaabs < 4:
2612 data.append(etafinal)
2613 nb_pass +=1
2614
2615
2616 print nb_pass
2617 gs1 = gridspec.GridSpec(2, 1, height_ratios=[5,1])
2618 gs1.update(wspace=0, hspace=0)
2619 ax = plt.subplot(gs1[0])
2620
2621 n, bins, patches = ax.hist(data, nbins, histtype='step', label='original')
2622 ax_c = ax.twinx()
2623 ax_c.set_ylabel('MadGraph5_aMC@NLO')
2624 ax_c.yaxis.set_label_coords(1.01, 0.25)
2625 ax_c.set_yticks(ax.get_yticks())
2626 ax_c.set_yticklabels([])
2627 ax.set_xlim([-4,4])
2628 print "bin value:", n
2629 print "start/end point of bins", bins
2630 plt.axis('on')
2631 plt.xlabel('weight ratio')
2632 plt.show()
2633
2634
2635
2636 if False:
2637 lhe = EventFile('unweighted_events.lhe')
2638 import matplotlib.pyplot as plt
2639 import matplotlib.gridspec as gridspec
2640 nbins = 100
2641
2642
2643 mtau, wtau = 1.777, 4.027000e-13
2644 nb_pass = 0
2645 data, data2, data3 = [], [], []
2646 for event in lhe:
2647 nb_pass +=1
2648 if nb_pass > 10000:
2649 break
2650 tau1 = FourMomentum()
2651 tau2 = FourMomentum()
2652 for part in event:
2653 if part.pid in [-12,11,16]:
2654 momenta = FourMomentum(part)
2655 tau1 += momenta
2656 elif part.pid == 15:
2657 tau2 += FourMomentum(part)
2658
2659 if abs((mtau-tau2.mass())/wtau)<1e6 and tau2.mass() >1:
2660 data.append((tau1.mass()-mtau)/wtau)
2661 data2.append((tau2.mass()-mtau)/wtau)
2662 gs1 = gridspec.GridSpec(2, 1, height_ratios=[5,1])
2663 gs1.update(wspace=0, hspace=0)
2664 ax = plt.subplot(gs1[0])
2665
2666 n, bins, patches = ax.hist(data2, nbins, histtype='step', label='original')
2667 n2, bins2, patches2 = ax.hist(data, bins=bins, histtype='step',label='reconstructed')
2668 import cmath
2669
2670 breit = lambda m : math.sqrt(4*math.pi)*1/(((m)**2-mtau**2)**2+(mtau*wtau)**2)*wtau
2671
2672 data3 = [breit(mtau + x*wtau)*wtau*16867622.6624*50 for x in bins]
2673
2674 ax.plot(bins, data3,label='breit-wigner')
2675
2676 ax.legend()
2677
2678 ax_c = ax.twinx()
2679 ax_c.set_ylabel('MadGraph5_aMC@NLO')
2680 ax_c.yaxis.set_label_coords(1.01, 0.25)
2681 ax_c.set_yticks(ax.get_yticks())
2682 ax_c.set_yticklabels([])
2683
2684 plt.title('invariant mass of tau LHE/reconstructed')
2685 plt.axis('on')
2686 ax.set_xticklabels([])
2687
2688 ax = plt.subplot(gs1[1])
2689 data4 = [n[i]/(data3[i]) for i in range(nbins)]
2690 ax.plot(bins, data4 + [0] , 'b')
2691 data4 = [n2[i]/(data3[i]) for i in range(nbins)]
2692 ax.plot(bins, data4 + [0] , 'g')
2693 ax.set_ylim([0,2])
2694
2695 tick = ax.get_yticks()
2696 ax.set_yticks(tick[:-1])
2697
2698
2699 plt.axis('on')
2700 plt.xlabel('(M - Mtau)/Wtau')
2701 plt.show()
2702