1
2
3 try:
4 import madgraph.madweight.particle_class as particle_class
5 import madgraph.various.misc as misc
6 except ImportError:
7 import internal.madweight.particle_class as particle_class
8 import internal.misc as misc
9 Particle = particle_class.Particle
10
11 import sys
12
14 """ define generic tool for maintained how to generate a sequential change of variable
15 this class in only defined in order to have common routine for ECS_sector and Blob-solution
16 """
17
19 """init generic variable """
20 self.num_fuse=0
21 self.sol_tag=tag
22
23 if def_step:
24 if type(def_step)==list:
25 self.step=def_step
26 else:
27 self.step=[def_step]
28 else:
29 self.step=[]
30
31
32
33
35 """ define a fuse part(Block '2' but with new particle) for the particle in the list
36 output_mode=1: return the particle
37 output_mode=2: return the particle and the unaligned propagator
38 """
39 lowercase='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
40 fuse_list_=list(fuse_list)
41
42 unaligned=[]
43 while 1:
44 if len(fuse_list_)==1:
45 break
46 if output_mode==1: return fuse_list_[0]
47 else: return fuse_list_[0],unaligned
48 else:
49 part1=fuse_list_.pop(0)
50 part2=fuse_list_.pop(0)
51 fuse_particle=Particle(lowercase[self.num_fuse],0,fuse=1)
52 fuse_particle.level=part1.level
53 if part1.level<part2.level:
54 fuse_particle.mother=part1.mother
55 unaligned.append(part2.mother)
56 else:
57 fuse_particle.mother=part2.mother
58 unaligned.append(part1.mother)
59 self.num_fuse+=1
60 fuse_list_.append(fuse_particle)
61
62 if(self.sol_tag=='blob'):
63 Block_B(self,'3',[part1,part2],fuse_particle)
64 else:
65 Block_sector(self,'3',[part1,part2],fuse_particle)
66
67 if output_mode==1:
68 return fuse_list_[0]
69 else:
70 return fuse_list_[0],unaligned
71
73 """ (re)ordrer so that the new order follow the generation order """
74
75 new_order=[]
76
77 ready=[]
78 ready+=main_sec.ext_content
79 control=0
80
81 while 1:
82 if len(self.step)==0:
83
84 break
85 control+=1
86 if control>len(self.step)+1:
87 sys.exit('ERROR: infinite loop detected in Level_generation.order_block()')
88
89
90
91
92
93
94
95 block=self.step.pop(0)
96 for particle in block.in_part:
97 if particle not in ready:
98 self.step.append(block)
99 suceed=0
100
101 break
102 else:
103 suceed=1
104
105 if not suceed:
106 continue
107
108 control=0
109
110 new_order.append(block)
111 for particle in block.out_part:
112 ready.append(particle)
113 for particle in block.in_part:
114 ready.remove(particle)
115
116 self.step=new_order
117
118
119
120
122 """ store the information of how to generate a blob """
123
124 - def __init__(self,blob_sec,solution=''):
125 """ initialize how_gen: dict: Particle-> related block
126 step: list of all needed block in the correct order
127 update link with the related blob
128 """
129
130 Level_generation.__init__(self,'blob')
131
132 self.blob_sec=blob_sec
133 blob_sec.solution.append(self)
134
135 self.opt=blob_sec.opt
136
137 self.unaligned=[]
138
139
140 if solution:
141 self.copy_solution(solution)
142 else:
143 self.how_gen={}
144 for part in blob_sec.content:
145 self.how_gen[part]=''
146
147
148
149
150
152 """ duplicate solution (no alias use) in order to modify it later """
153
154
155 self.num_fuse=solution.num_fuse
156 self.how_gen={}
157 self.ready_to_enter=list(solution.ready_to_enter)
158
159 self.num_fuse=solution.num_fuse
160 self.step=list(solution.step)
161 self.how_gen=dict(solution.how_gen)
162 self.unaligned=list(solution.unaligned)
163
164 a=self.step.pop(0)
165 if self.step==solution.step:
166 sys.exit('stop same object in step')
167 self.step.insert(0,a)
168 self.how_gen[1]=1
169 if self.how_gen==solution.how_gen:
170 sys.exit('stop same object in how_gen')
171 del self.how_gen[1]
172
173
174
175
176
178 """ (blob)->None : complete blob_sec.sol
179
180 * find tree solutions:
181 1) this solutions maximize the number of propagator generated following BW
182 2) this solutions maximize the number of external particle generated following tf (i.e. all execpt neutrino)
183 3) this solutions try to be an intermediate solution between the two
184 * In practise, we start to construct a 'beta' solution, which one will identify globaly the structure of the solution
185 The beta try to made the more local change, and don't consider E case (but have E* tag for an D which can pass in E)
186 * Secondly we will apply modification to this beta, to pass in each solution case
187 The first solution will be the first one with improvment in 'A' case and will restore 'E'(and extend E) case
188 the second one will change all 'D','E' in '1', with little modification in 'A' case
189 The third solution will be essentially the beta without 'E' (only D for visible case)"""
190
191
192 self.find_beta_solution(blob_sec)
193 self.order_block(blob_sec)
194
195 if self.opt.use_sol_type_1:
196 sol1=Blob_solution(blob_sec,self)
197 if self.opt.use_sol_type_2:
198 sol2=Blob_solution(blob_sec,self)
199 if self.opt.use_sol_type_3:
200 sol3=self
201
202
203
204 if self.opt.use_sol_type_1:
205 sol1.pass_in_solution(1)
206 if self.opt.use_sol_type_2:
207 sol2.pass_in_solution(2)
208 if self.opt.use_sol_type_3:
209 sol3.pass_in_solution(3)
210 else:
211 blob_sec.solution.remove(self)
212
213 if not (self.opt.use_sol_type_1 or self.opt.use_sol_type_2 or self.opt.use_sol_type_3):
214 sys.exit('FATAL ERROR: At least one solution for Blob generation must be authorized')
215
216
217
218
219
221 """ find a first solution to resolve the blob.
222 The idea is to take the more local possibility in all case
223 this is perhaps not the best solution but it's only the beginning of the resolution
224 Secondly we will not defined 'final' block but some more generic one (like E*: restriction at one level of E)
225 """
226
227 self.ready_to_enter=list(blob_sec.ext_content)
228 self.ready_to_enter.reverse()
229 step=0
230 while 1:
231 step+=1
232 if step>40:
233 sys.exit('ERROR: infinite loop detected in Blob_solution.find_beta_solution()')
234 if len(self.ready_to_enter)<2:
235 break
236
237
238
239
240
241 part1=self.ready_to_enter.pop(0)
242
243 part2=part1.twin
244
245 if part2 not in self.ready_to_enter:
246
247 self.ready_to_enter.append(part1)
248 continue
249
250 solution=self.resolve_piece(blob_sec,[part1,part2])
251
252
253
254 if self.how_gen[blob_sec.main]=='':
255
256 Block_B(self,'0',[blob_sec.main],[])
257
258
260 "find the 'first' solution for this piece"
261
262
263 mother1=in_part[0].mother
264 mother_twin=mother1.twin
265
266
267
268 if not( in_part[0].external or in_part[1].external):
269
270 result=Block_B(self,'2',in_part,mother1)
271 return result
272
273
274 self.sol_type=''
275
276 for particle in in_part:
277 if particle.neutrino:
278
279
280 twin=particle.twin
281
282 motherX=particle
283 mother_list=[]
284 for X in range(1,4):
285
286 motherX=motherX.mother
287 if motherX==0:
288
289 stop='Not_exist'
290 break
291
292 if blob_sec.contains_particle(motherX):
293 if self.how_gen[motherX]=='':
294 mother_list.append(motherX)
295
296 if mother_list[-1].twin!=0 and mother_list[-1].twin.neutrino:
297
298 stop='neut'
299 break
300 else:
301
302
303 stop=self.how_gen[motherX]
304 break
305 else:
306
307 stop='Not_exist'
308 break
309
310 if len(mother_list)==0:
311 Block_B(self,'0',[particle],[])
312 elif len(mother_list)==1:
313 block=Block_B(self,'C',[particle,twin],[mother_list[0]])
314 block.give_stop_reason(stop)
315 self.treat_conflicting_block(block)
316 elif len(mother_list)==2:
317 block=Block_B(self,'B',[particle,twin,mother_list[0].twin],[mother_list[-1]])
318 block.give_stop_reason(stop)
319 elif len(mother_list)==3:
320 block=Block_B(self,'A',[particle,twin,mother_list[0].twin,mother_list[1].twin],[mother_list[-1]])
321 return block
322
323
324
325 if (not (in_part[0].external and in_part[1].external)):
326 if in_part[0].external:
327 particle=in_part[0]
328 propa=in_part[1]
329 else:
330 particle=in_part[1]
331 propa=in_part[0]
332 if particle.tf_level<2:
333
334 result=Block_B(self,'1',in_part,[mother1])
335 else:
336
337 result=Block_B(self,'D',in_part,[mother1])
338 return result
339
340
341
342
343 if in_part[0].tf_level<2 and in_part[1].tf_level<2:
344
345 result=Block_B(self,'1',in_part,[mother1])
346 elif in_part[0].tf_level<2 or in_part[1].tf_level<2:
347
348
349 result=Block_B(self,'D',in_part,[mother1])
350
351 elif not(in_part[0].mass and in_part[1].mass):
352
353
354 result=Block_B(self,'E*',in_part,[mother1])
355 else:
356
357
358 result=Block_B(self,'D',in_part,[in_part[0].mother])
359 return result
360
361
363 """ if a 'C' block is block by a 'A' block it's sometimes more powerful to degrade the 'A' in 'B'
364 if the 'C' can be upgrated to 'A'"""
365
366
367 if block.stop!='A':
368 return
369
370
371
372 try:
373 mother1=block.out_part[0].mother
374 mother2=mother1.mother
375 if self.how_gen[mother2].chgt_var not in ['','0','1','2','D']:
376 return
377 except:
378 return
379
380
381
382 blockA=self.how_gen[mother1]
383
384 new_in=blockA.in_part
385 new_in.remove(block.out_part[0])
386 blockA.redefine_block(self,'B',new_in,out_part[0].twin)
387
388 new_in=block.in_part+[out_part[0].twin,mother1.twin]
389 block.redefine_block(self,'A',new_in,mother2)
390
391
392
393
394
395
422
424 """ convert all 'E*' and all 'D' in '1' block """
425
426
427 all_block=list(self.step)
428 for block in all_block:
429 if self.blob_sec.content[0].width < self.opt.force_nwa:
430 continue
431
432 if block.chgt_var in ['E*','D']:
433 block.change_chgt_var(self,'1')
434
435
437 """ convert all 'E*' in 'D' """
438
439
440 for block in self.step:
441 if block.chgt_var in ['E*']:
442 block.change_chgt_var(self,'D')
443
444
446 """ put the A/D/E propagator in place to minize problem with thin transfer function"""
447
448 num_propa={'A':3,'D':1,'E*':2}
449 num_propa=num_propa[chgt_var]
450 new_chgt_var={'A':'A','D':'D','E*':'E'}
451 new_chgt_var=new_chgt_var[chgt_var]
452
453
454
455
456
457
458
459
460
461
462
463
464
465 step2=0
466 all_block=list(self.step)
467 for block in all_block:
468 step2+=1
469 if block.chgt_var!=chgt_var:
470 continue
471 if block not in self.step:
472 continue
473
474
475
476
477 thin=[]
478
479
480 try:
481 motherX=block.neut_content[0]
482 except:
483 motherX=block.in_part[0]
484 while 1:
485 motherX=motherX.mother
486 if self.blob_sec.contains_particle(motherX)==0:
487 break
488 if not( self.how_gen[motherX].chgt_var in ['0','1','2','D'] or self.how_gen[motherX]==block):
489 break
490
491
492 for i in range(0,len(thin)+1):
493
494
495
496
497
498 if i==len(thin) and i<num_propa:
499 thin.append(motherX)
500 elif(motherX.width<thin[i].width and motherX.channel=='S'):
501 thin.insert(i,motherX)
502 if len(thin)>num_propa:
503 thin=thin[:num_propa]
504 break
505
506
507
508
509
510
511
512 propa_in=[thin[0]]
513 for i in range(1,len(thin)):
514 for j in range(0,len(propa_in)+1):
515 if j==len(propa_in):
516 propa_in.append(thin[i])
517 elif(thin[i].level<propa_in[j].level):
518 propa_in.insert(j,thin[i])
519 break
520
521
522 if (block.chgt_var=='E*' and (not self.opt.blob_fuse) and len(propa_in)==2):
523
524 propa_in=[block.in_part[0].mother,block.in_part[0].mother.mother]
525
526
527
528
529
530
531
532 fuse_list=[]
533 step=0
534 try:
535 motherX=block.neut_content[0]
536 except:
537 motherX=block.in_part[0]
538
539 part_in=[motherX]
540 while 1:
541 motherXbut1=motherX
542 motherX=motherX.mother
543
544 if step==len(propa_in):
545 break
546 if self.blob_sec.contains_particle(motherX)==0:
547 sys.exit('ERROR: unusual error in Blob_solution.expand_block: debug this routine (error type 1)')
548 if not( self.how_gen[motherX].chgt_var in ['0','1','2','D'] or self.how_gen[motherX]==block):
549 sys.exit('ERROR: unusual error in Blob_solution.expand_block: debug this routine (error type 2)')
550
551 if motherX in propa_in:
552 step+=1
553 if self.how_gen[motherX]!=block:
554 self.how_gen[motherX].del_from_sol(self)
555 if fuse_list:
556 fuse_part=self.define_fuse_region(fuse_list)
557 part_in.append(fuse_part)
558 fuse_list=[]
559 else:
560 part_in.append(motherXbut1.twin)
561 elif fuse_list:
562 self.how_gen[motherX].del_from_sol(self)
563 fuse_list.append(motherX.twin)
564 else:
565 self.how_gen[motherX].del_from_sol(self)
566 fuse_list=[motherXbut1.twin,motherX.twin]
567
568
569
570 if num_propa==len(part_in)-1:
571 block.redefine_block(self,new_chgt_var,part_in,propa_in[0])
572 elif chgt_var=='E*':
573
574 block.change_chgt_var(self,'D')
575 else:
576 sys.exit('ERROR: unusual error in Blob_solution.expand_block: debug this routine (error type 3)')
577
578
579
581 """ delete blok '1' but only if the particle is an external one!"""
582
583 for particle in particle_list:
584 if particle.external and self.how_gen[particle].chgt_var=='1':
585 self.how_gen[particle].del_from_sol[self]
586
587
588
589
590
591
592
593
595 """ function for debugging: print how_gen"""
596 print "how_gen"
597 list=self.how_gen.items()
598 for i in range(0,len(list)):
599 try:
600 print '{'+str(list[i][0].MG),':'+str(list[i][1].chgt_var)+'}',
601 except:
602 print '}',
603 print
604
605
607 text='blob generation: '
608 for block in self.step:
609 text+='['+block.chgt_var+'|'
610 for particle in block.in_part:
611 text+=str(particle.MG)+' '
612 text+=':'
613 for particle in block.out_part:
614 text+=str(particle.MG)+' '
615 text+='] '
616
617
618 return text
619
620
622 """define:store information on a Block.
623 This is a simple version of block dedicated for ECS
624 This is the basis for the blob dedicated
625 """
626
627 - def __init__(self,sol_sec,chgt_var,input_propa,output_propa):
628
629 self.sol_sec=sol_sec
630 self.chgt_var=chgt_var
631 self.in_part=input_propa
632 if type(output_propa)==list:
633 self.out_part=output_propa
634 else:
635 self.out_part=[output_propa]
636 self.opt=sol_sec.opt
637 self.unaligned=[]
638
639
640 self.neut_content=[]
641 self.num_neut=0
642 for particle in input_propa:
643 if particle.neutrino:
644 self.neut_content.append(particle)
645 self.num_neut+=1
646
647
648 self.stop=''
649
650
651 sol_sec.step.append(self)
652 self.def_order_content()
653
655 """ store the stop information (why not a more general change of variable) """
656 self.stop=message
657
658
660 """ define (in the corect order) the particle used in this ECS
661 only for fuse sector (routine overwirtted in other case)
662 """
663
664
665
666 if self.chgt_var=='3':
667 self.order_content=self.in_part+self.out_part
668 self.chgt_var='2'
669
670
671
673 """ print routine """
674
675 text="["+str(self.chgt_var)+ ' |'
676 for particle in self.in_part:
677 text+=str(particle.MG)+','
678 text=text[:-1]+' :'
679 for particle in self.out_part:
680 text+=str(particle.MG)+','
681
682 return text[:-1]+']'
683
684
686 """ Define a Block dedicated to be an ECS central part"""
687
688 - def __init__(self,sol_sec,chgt_var,input_part):
693
694
696 """ define (in the correct order) the particle used in this ECS
697 This routine is overwrited for block linked to blob
698 """
699
700 if self.chgt_var=='a':
701 self.order_content=self.in_part
702 return
703
704
705 ext_content=[]
706 propa_content=[]
707 neut_content=[]
708 self.order_content=[]
709
710 for particle in self.in_part:
711 if particle.neutrino:
712 neut_content.append(particle)
713 continue
714
715 propa_content.append(particle.mother)
716 ext_content.append(particle)
717
718 self.order_content=neut_content+ext_content+propa_content
719
720
721 if self.chgt_var=='e':
722 neut_in_ecs=neut_content[0]
723 self.order_content.append(neut_in_ecs.all_mother()[-1])
724
725
726
727
728
729
731
732 if self.chgt_var=='a':
733 unaligned=self.in_part[0].all_mother()
734 for part in self.in_part[1].all_mother():
735 if part not in unaligned:
736 unaligned.append(part)
737 self.unaligned=unaligned+self.in_part
738 return
739
740
741 aligned=[part.mother for part in self.in_part if part.neutrino==0]
742 if self.chgt_var=='a':
743 aligned.append(self.order_content[-1])
744
745 unaligned=[]
746 for i in range(0,self.num_neut):
747 for part in self.order_content[i].all_mother():
748 if part not in aligned+unaligned:
749 unaligned.append(part)
750
751 self.unaligned=unaligned
752
754 """ Define a Block dedicated to be in a blob"""
755
756 - def __init__(self,sol_sec,chgt_var,input_propa,output_propa,unaligned=[]):
762
763
765 """ put the solution status uptodate with this block definition """
766
767 for particle in self.in_part:
768 try:
769 sol_sec.ready_to_enter.remove(particle)
770 except:
771 pass
772 if particle.external:
773 sol_sec.how_gen[particle]=self
774 if particle.mother and particle.mother not in self.out_part and self.chgt_var!='0':
775 if sol_sec.blob_sec.contains_particle(particle.mother):
776 sol_sec.how_gen[particle.mother]=self
777 for particle in self.out_part:
778
779
780 if sol_sec.blob_sec.contains_particle(particle.mother):
781 if sol_sec.how_gen[particle.mother]=='':
782 sol_sec.ready_to_enter.append(particle)
783 sol_sec.how_gen[particle]=self
784
785
787 """ define (in the corect order) the particle used in this blob """
788
789 propa_content=[]
790
791
792 if self.chgt_var=='3':
793 self.order_content=self.in_part+self.out_part
794 self.chgt_var='2'
795 elif self.chgt_var=='0':
796 self.order_content=self.in_part
797 elif self.chgt_var=='E':
798 propa_content=[self.in_part[0].mother,self.in_part[2].mother]
799 if self.in_part[0].mass:
800 self.order_content=self.in_part+propa_content
801 else:
802 self.order_content=[self.in_part[1],self.in_part[0],self.in_part[2]]+propa_content
803 elif isinstance(self.in_part[0].MG, basestring):
804 self.order_content=self.in_part+[self.in_part[0].mother]
805 try:
806 self.order_content.append(self.in_part[2].mother)
807 except:
808 pass
809 elif isinstance(self.in_part[1].MG, basestring):
810 self.order_content=self.in_part+[self.in_part[1].mother]
811 try:
812 self.order_content.append(self.in_part[2].mother)
813 except:
814 pass
815 else:
816 for particle in self.in_part :
817 if particle.mother not in propa_content:
818 propa_content.append(particle.mother)
819 self.order_content=self.in_part+propa_content
820
821
823 """ change the changement of variable associated """
824 equivalent_class=[['E*','E','D','1','2']
825
826 ]
827
828 if self.sol_sec==sol_sec:
829 obj=self
830 else:
831
832 try:
833 sol_sec.step.remove(self)
834 except:
835 pass
836 obj=Block_B(sol_sec,self.chgt_var,self.in_part,self.out_part)
837 obj.def_unaligned()
838
839 for i in range(0,len(equivalent_class)):
840 if obj.chgt_var in equivalent_class[i]:
841 if new_chgt_var in equivalent_class[i]:
842 obj.chgt_var=new_chgt_var
843 obj.def_unaligned()
844 if obj.chgt_var!=new_chgt_var:
845 print 'WARNING: unexpected modification:'
846 print ' pass from',[obj.chgt_var],'to',[new_chgt_var]
847 print ' there are strictly non equivalent: but we go on anyway'
848 obj.chgt_var=new_chgt_var
849
851 """ associate in self.unaligned the particle with unaligned peaks """
852
853 if self.chgt_var in ['1','2']:
854 self.unaligned=self.out_part[0]
855 elif self.chgt_var=='E':
856 self.unaligned=[self.in_part[0],self.in_part[1]]
857 elif self.chgt_var=='D':
858 tag1=self.in_part[0].MG
859 tag2=self.in_part[1].MG
860 if tag1<0:
861 self.unaligned=self.in_part[1]
862 elif tag2<0:
863 self.unaligned=self.in_part[0]
864 else:
865 if tag1>tag2:
866 tag1,tag2=tag2,tag1
867 self.unaligned='first_d_'+str(tag1)+'_'+str(tag2)
868
886
887
889 """ supress corectly the block of the solutions """
890
891 sol_sec.step.remove(self)
892
893
894 for particle in self.in_part:
895 if particle.external:
896 sol_sec.how_gen[particle]=''
897 sol_sec.ready_to_enter.append(particle)
898
899 for particle in self.out_part:
900 sol_sec.how_gen[particle]=''
901 try:
902 sol_sec.ready_to_enter.remove(particle)
903 except:
904 pass
905
906 if self.sol_sec==sol_sec:
907
908 del self
909