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