1
2
3
4 from __future__ import absolute_import
5 from six.moves import range
6 try:
7 import madgraph.madweight.blob_solution as blob_solution
8 except ImportError:
9 import internal.madweight.blob_solution as blob_solution
10
11 Level_generation = blob_solution.Level_generation
12 Blob_solution = blob_solution.Blob_solution
13 Block_ECS =blob_solution.Block_ECS
14 Block_sector =blob_solution.Block_sector
15 Block_B =blob_solution.Block_B
16
17 import sys
18
20
22
23 self.content={}
24 self.prop_content=[]
25 self.ext_content=[]
26 self.neut_content=[]
27 self.num_propa=0
28 self.ext_part=0
29 self.num_neut=0
30 self.config=0
31
32
33
34 - def add_content(self,MG_id,object):
35 "add a element in the diagram"
36 self.content[int(MG_id)]=object
37
38 if object.external and int(MG_id) > 2:
39 self.ext_content.append(object)
40 self.ext_part+=1
41 elif not object.external:
42 self.prop_content.append(object)
43 self.num_propa+=1
44
45
47 "define neutrino content"
48 self.neut_content=[]
49 for ExtPart in self.ext_content :
50 if(ExtPart.neutrino):
51 self.neut_content.append(ExtPart)
52 self.num_neut=len(self.neut_content)
53
54
56 """ complete self.content[i].level:number a propa before a external particle, and the number of propa before
57 (with himself for a propa)"""
58
59
60 for i in range(1,self.num_propa+1):
61 propa=self.prop_content[-i]
62
63 if(propa.mother in self.prop_content and propa.channel=='S'):
64 propa.level=propa.mother.level+1
65 elif(propa.channel=='T'):
66 propa.level=0
67 else:
68 propa.level=1
69
70
71 self.content[1].level=0
72 self.content[2].level=0
73
74 for ExtPart in self.ext_content:
75 if ExtPart.mother:
76 ExtPart.level=ExtPart.mother.level
77 else:
78 ExtPart.level=0
79
80
82 "return list with external particle ordering following level"
83
84
85 dict_level_to_part={}
86 for particle in self.ext_content:
87 if particle.level in list(dict_level_to_part.keys()):
88 dict_level_to_part[particle.level].append(particle)
89 else:
90 dict_level_to_part[particle.level]=[particle]
91
92
93 self.ext_content=[]
94 level=-1
95 while 1:
96 if len(dict_level_to_part)==0:
97 break
98 level+=1
99 self.ext_content+=dict_level_to_part.pop(level,[])
100
101 - def contains_particle(self,particle):
102 """ check if tha particle is in the diagram """
103
104 if type(self.content)== dict:
105 if particle.MG in self.content:
106 return 1
107 else:
108 return 0
109 elif type(self.content)== list:
110 if particle in self.content:
111 return 1
112 else:
113 return 0
114
115
116
118 """ The ECS sector.
119 The parenty to Blob_solution is slightly dangerous, lot of variables are different, but some part are equivalent
120 lot of time ECS play the two role: Blob and Blob solution
121 """
122
123 - def __init__(self,diag,chgt_var,neut_in_ecs,unaligned):
124 """ create the ECS SECTOR
125 neut_in_ecs are the fondamental particle of the class (and so not always neutrino)
126 """
127 neut_in_class={'a':0,'b':1,'c':1,'d':2,'e':2,'f':2,'g':2}
128 intrinsec_in_class={'a':2,'b':1,'c':1,'d':2,'e':2,'f':2,'g':2}
129
130
131 diagram.__init__(self)
132 Level_generation.__init__(self,'ecs')
133 self.fuse=0
134
135 self.MG_sec=diag
136 self.chgt_var=chgt_var
137 if type(neut_in_ecs)==list:
138 self.main_content=neut_in_ecs
139 else:
140 self.main_content=[neut_in_ecs]
141 self.unaligned=unaligned
142
143 self.num_neut=neut_in_class[chgt_var]
144 self.intrinsec=intrinsec_in_class[chgt_var]
145 self.opt=diag.opt
146
148 """ define the blob associated to this Enlarged constraint sector """
149
150 if not propa_in_ecs:
151 propa_in_ecs=self.main_content
152
153 self.blob_content=[]
154
155
156
157
158
159 for i in range(0,self.intrinsec):
160
161
162 if i==0:
163 combine_all_mother=[]
164 combine_all_mother+=propa_in_ecs[i].all_mother()
165 continue
166
167 for mother in propa_in_ecs[i].all_mother():
168 if mother not in combine_all_mother:
169 combine_all_mother.append(mother)
170
171
172 for particle in combine_all_mother:
173
174 for desint in particle.des:
175 if desint not in combine_all_mother and desint not in propa_in_ecs:
176 blob_sector(desint,diag,ECS_sec=self)
177
178
179
180 for i in range(-1*diag.num_propa,0):
181 propa=diag.content[i]
182
183 if propa.channel=='T':
184 for desint in propa.des:
185 if desint.external:
186 if desint not in propa_in_ecs:
187 blob_sector(desint,diag,ECS_sec=self)
188
189 elif(desint not in combine_all_mother):
190 blob_sector(desint,diag,ECS_sec=self)
191
192 for particle in diag.prop_content+diag.ext_content:
193 if particle.mother==0:
194 if particle not in combine_all_mother and particle not in propa_in_ecs:
195 blob_sector(particle,diag,ECS_sec=self)
196
197
198
200 """ 1) define completely the change of variable for the enlarged ECS
201 -find which propagator aligned,...
202 2) define equivalent solution if any (B->C)
203 """
204
205 if self.num_neut==0:
206
207 if self.opt.use_ecs_a:
208 solution=Block_ECS(self,'a',self.main_content)
209 return [self]
210 else:
211 return []
212 elif self.num_neut==1:
213
214 if self.opt.use_ecs_b or self.opt.use_ecs_c:
215 output=self.equivalent_ECS_1neut()
216 return output
217 else:
218 return []
219 else:
220
221
222 if self.opt.use_ecs_d or self.opt.use_ecs_e or self.opt.use_ecs_f :
223 output=self.equivalent_ECS_2neut()
224 return output
225 else:
226 return []
227
228
229
231 """ 1) define completly the change of variable for the enlarged ECS
232 -find which propagator aligned,...
233 2) define equivalent solution if any (B->C)
234 """
235
236 thiner=self.main_content[0].mother.width
237 part_thin=self.main_content[0].mother
238 thiner_bef_m0=500
239 thiner_m0=500
240 madeC=0
241 motherX=self.main_content[0]
242
243 while 1:
244 motherX=motherX.mother
245 if motherX==0:
246 break
247
248 if motherX.width<thiner and motherX.channel=='S':
249 thiner=motherX.width
250 part_thin=motherX
251
252
253 try:
254 if motherX.twin.external and motherX.twin.mass==0:
255 if motherX.twin.tf_level>1 and motherX.channel=='S':
256 madeC=1
257 if motherX.mother.width<thiner_m0:
258 thiner_m0=motherX.mother.width
259 if thiner<thiner_bef_m0:
260 thiner_bef_m0=thiner
261 except:
262 pass
263
264
265 if madeC:
266 New_sol=ECS_sector(self.MG_sec,'c',self.main_content,self.unaligned)
267 fuse_list=[]
268 motherX=self.main_content[0]
269 while motherX.width!=thiner_bef_m0:
270 fuse_list.append(motherX.twin)
271 motherX=motherX.mother
272 fuse_particle1=New_sol.define_fuse_region(fuse_list)
273 fuse_list=[]
274 while motherX.width!=thiner_m0:
275 fuse_list.append(motherX.twin)
276 motherX=motherX.mother
277 fuse_particle2=New_sol.define_fuse_region(fuse_list)
278 Block_ECS(New_sol,'c',self.main_content+[fuse_particle1,fuse_particle2])
279 New_sol.order_block(New_sol)
280
281
282
283 fuse_list=[]
284 motherX=self.main_content[0]
285 while part_thin!=motherX:
286 fuse_list.append(motherX.twin)
287 motherX=motherX.mother
288 fuse_particle=self.define_fuse_region(fuse_list)
289 Block_ECS(self,'b',self.main_content+[fuse_particle])
290 self.order_block(self)
291
292
293 sol=[]
294 if self.opt.use_ecs_b:
295 sol.append(self)
296 if madeC and self.opt.use_ecs_c:
297 sol.append(New_sol)
298
299 return sol
300
301
302
304 """ 1) define completly the change of variable for the enlarged ECS
305 -find which propagator aligned,...
306 Each change of variable are factorized!!!
307 """
308 total_propa,lim1,lim2=self.main_content[0].unaligned_propa(self.main_content[1],0)
309 lim=[lim1,lim2]
310 fuse_particle=[]
311
312
313
314 if self.chgt_var=='d':
315
316 if not self.opt.use_ecs_d:
317 return []
318
319 for i in [0,1]:
320 thiner=500
321 thiner2=600
322
323 if self.opt.ecs_fuse:
324 motherX=self.main_content[i]
325 for j in range(0,lim[i]):
326 motherX=motherX.mother
327 if motherX.width<thiner and motherX.channel=='S':
328 thiner2=thiner
329 thiner=motherX.width
330 elif motherX.width<thiner2 and motherX.channel=='S':
331 thiner2=motherX.width
332
333 if thiner==500:
334 thiner=self.main_content[i].mother.width
335 thiner2=self.main_content[i].mother.mother.width
336 if thiner2==500:
337 if thiner!=self.main_content[i].mother.width:
338 thiner2=self.main_content[i].mother.mother.width
339 elif self.main_content[i].mother.channel=='S_flat':
340 thiner2=self.main_content[i].mother.mother.width
341 else:
342 thiner2=self.main_content[i].mother.mother.width
343
344
345 motherX=self.main_content[i]
346 fuse_list=[]
347 fuse_with_this_neut=0
348 while fuse_with_this_neut<2:
349 fuse_list.append(motherX.twin)
350 motherX=motherX.mother
351 if motherX==0:
352 break
353 if motherX.width in [thiner,thiner2]:
354 fuse=self.define_fuse_region(fuse_list)
355 fuse_particle.append(fuse)
356 fuse_list=[]
357 fuse_with_this_neut+=1
358 Block_ECS(self,'d',self.main_content+fuse_particle)
359 self.order_block(self)
360 return [self]
361
362
363
364 elif self.chgt_var=='e':
365
366 if not self.opt.use_ecs_e:
367 return []
368
369 for i in [0,1]:
370
371 if self.opt.ecs_fuse:
372 motherX=self.main_content[i].mother
373 thiner=motherX.width
374 for j in range(0,lim[i]-1):
375 motherX=motherX.mother
376 if motherX.width<thiner and motherX.channel=='S':
377 thiner=motherX.width
378 else:
379 thiner=self.main_content[i].mother.width
380
381 motherX=self.main_content[i]
382 fuse_list=[]
383 while 1:
384 fuse_list.append(motherX.twin)
385 motherX=motherX.mother
386 if motherX.width==thiner:
387 fuse=self.define_fuse_region(fuse_list)
388 fuse_particle.append(fuse)
389 break
390 a=Block_ECS(self,'e',self.main_content+fuse_particle)
391 self.order_block(self)
392
393
394
395
396 return [self]
397
398
399
400 elif self.chgt_var=='f' or self.chgt_var=='g':
401
402 if not self.opt.use_ecs_f:
403 return []
404
405 twin_part=[]
406 twin_part.append(self.main_content[0].twin)
407 twin_part.append(self.main_content[1].twin)
408 Block_ECS(self,self.chgt_var,self.main_content+twin_part)
409 self.order_block(self)
410 return [self]
411
412
414 """ take care of the position of the other neutrino in order to have a more
415 serious definition of the number of un-aligned variable
416
417 this routine is designed for update the 1 neutrino case
418 """
419
420 control=0
421 for neutrino in self.main_content:
422 motherX=neutrino
423
424 if motherX.neutrino==0:
425 try:
426 neutrino2,step=motherX.twin.detect_neut_in_decay()
427 if step<3 and neutrino2:
428 self.unaligned+=3-step
429 except:
430 pass
431
432 while 1:
433 motherX=motherX.mother
434 if motherX==0:
435 break
436
437 try:
438 neutrino2,step=motherX.twin.detect_neut_in_decay()
439 except:
440 continue
441 if neutrino2==0:
442 continue
443 if neutrino2 in self.main_content:
444 control+=1
445 if control==2:
446 break
447 else:
448 continue
449 if step<3:
450 self.unaligned+=3-step
451
452
454
455 new_order=[]
456 step=1
457 while 1:
458 step+=1
459 if len(self.step)==1:
460 break
461 if step>20:
462 sys.exit('''ERROR: infinite loop detected in ECS_sector.order_block ''')
463
464 block=self.step.pop(0)
465
466 if block.chgt_var not in ['2','3']:
467 self.step.append(block)
468 else:
469 new_order.append(block)
470 new_order.append(self.step[0])
471 self.step=new_order
472
473
474
475
476
478 """ return some information about the ECS and the associated blob """
479 num_in_part={'a':2,'b':2,'c':3,'d':6,'e':4,'f':4,'g':4}
480
481 text='\t** Enlarged Contraint Sector global information **\n\n'
482 text+= 'Class: '+self.chgt_var.upper()+'\n'
483 text+='particle in ECS : '
484 for i in range(0,num_in_part[self.chgt_var]):
485 part=self.step[-1].order_content[i]
486 if i%3==0 and i!=0:
487 text+='\n\t\t\t\t '
488 if part.external:
489 if part.neutrino:
490 text+=str(part.MG)+'(missing)\t'
491 else:
492 text+=str(part.MG)+'(visible)\t'
493 elif type(part.MG)==str:
494 text+=str(part.MG)+'(fuse)\t'
495 else:
496 text+=str(part.MG)+'(propagator)\t'
497
498 text+='\nblob linked are generated by :'
499 for blob in self.blob_content:
500 if blob.main.MG<0:
501 text+=str(blob.main.MG)+'\t'
502 text+='\n'
503 return text
504
506 text= 'ECS info:'
507 text+= 'Class: '+str(self.chgt_var)+' particles in ECS : '
508 for part in self.ext_content:
509 text+=str(part.MG)+'\t'
510 text+='|| linked blob(\'s): '
511 try:
512 for blob in self.blob_content:
513 text+=str(blob.main.MG)+'\t'
514 except:
515 text+='not yet defined'
516 return text
517
518
519
520
521
522
523
524
526 """ blob structure """
527
528 - def __init__(self,particle,diag,ECS_sec=''):
529 """create completly a blob if he is not defined already """
530
531
532 if particle.MG in diag.blob_content:
533 self=diag.blob_content[particle.MG]
534 self.put_in_ecs(ECS_sec)
535 return
536 elif particle.MG in range(0,diag.num_init):
537 return None
538 elif not particle.external:
539 if not particle.channel.startswith('S'):
540 return None
541
542
543 diagram.__init__(self)
544
545 diag.blob_content[particle.MG]=self
546
547 self.put_in_ecs(ECS_sec)
548
549 self.main=particle
550 self.generate_content()
551 self.solution=[]
552
553 self.opt=diag.opt
554
555
557 """ put this blob in the blob content of ECS """
558
559 if ECS_sec:
560 if self not in ECS_sec.blob_content:
561 ECS_sec.blob_content.append(self)
562
564 """ import all the information for the blog """
565 self.content=[self.main]
566 for particle in self.content:
567 if particle.external:
568 self.ext_content.append(particle)
569 self.ext_part+=1
570 if particle.neutrino:
571 self.neut_content.append(particle)
572 self.num_neut+=1
573 else:
574 self.prop_content.append(particle)
575 self.num_propa+=1
576 self.content+=particle.des
577 self.order_in_level()
578
579
581 """ find a first solution to resolve the blob.
582 The idea is to take the more local possibility in all case
583 this is perhaps not the best solution but it's only the beginning of the resolution"""
584 sol1=Blob_solution(self)
585 sol1.find_all_solutions(self)
586 self.supress_identical_solution()
587
588
590 """ supress identical solution """
591
592 del_sol=[]
593 for i in range(0,len(self.solution)):
594 for j in range(i+1,len(self.solution)):
595 if str(self.solution[i])==str(self.solution[j]):
596 del_sol.append(i)
597 break
598 for i in range(0,len(del_sol)):
599 del self.solution[del_sol[i]-i]
600
601
603 text= 'Blob details: main '+str(self.main.MG)+'\n'
604 for solution in self.solution:
605 text+=str(solution)+'\n'
606 return text
607
608
610 """ modify version of ECS sector, returning the different
611 possibility of unalignment in the black box
612 (usefull for multichannel mode)
613 """
614
616 """
617 define completely the change of variable for the enlarged ECS
618 - return all the possible ECS changing the particles entering in the B case
619 - define equivalent soltution if any (B->C)
620 """
621
622 sol=[]
623 fuse_list=[self.main_content[0].twin]
624 for propagator in self.main_content[0].all_mother():
625 if propagator.channel.startswith('T'):
626 break
627
628 if self.opt.use_ecs_b:
629 New_sol=ECS_sector(self.MG_sec,'b',self.main_content,self.unaligned)
630 fuse_particle=New_sol.define_fuse_region(fuse_list)
631 Block_ECS(New_sol,'b',self.main_content+[fuse_particle])
632 New_sol.order_block(New_sol)
633 sol.append(New_sol)
634
635
636 if self.opt.use_ecs_c:
637 sol+=self.equivalent_ECS_passinC(propagator,fuse_list)
638
639
640 fuse_list.append(propagator.twin)
641
642
643 return sol
644
645
647 """ check if those information can create a C block and define it
648 propa1: first propagator than should enter in the C block
649 fuse1: list of particles following this propa and should be fuse
650 """
651
652 particle2=propa1.twin
653 if not particle2 or particle2.mass:
654 return []
655 if particle2.MG<3:
656 return []
657 propa2=propa1.mother
658 if propa2 == 0 or propa2.channel.startswith('T'):
659 return []
660
661 New_sol=ECS_sector(self.MG_sec,'c',self.main_content,self.unaligned)
662 fuse=self.define_fuse_region(fuse1)
663 Block_ECS(New_sol,'c',self.main_content+[fuse,particle2])
664 New_sol.order_block(New_sol)
665
666 return [New_sol]
667
669 """ 1) define completely the change of variable for the enlarged ECS
670 -find which propagator aligned,...
671 Each change of variable are factorized!!!
672 """
673
674 if self.chgt_var!='d':
675 return ECS_sector_no_multi_channel.equivalent_ECS_2neut(self)
676
677 if not self.opt.use_ecs_d:
678 return []
679
680 sol=[]
681
682
683
684 possible_propa_1=[propa for propa in self.main_content[0].all_mother() \
685 if propa not in self.main_content[1].all_mother() ]
686 possible_propa_2=[propa for propa in self.main_content[1].all_mother() \
687 if propa not in self.main_content[0].all_mother() ]
688
689 fuse_list1_1=[self.main_content[0].twin]
690 for propagator1_1 in possible_propa_1:
691 fuse_list1_2=[propagator1_1.twin]
692 for propagator1_2 in propagator1_1.all_mother():
693 if propagator1_2 not in possible_propa_1 or propagator1_2.channel.startswith('T'):
694 break
695 fuse_list2_1= [self.main_content[1].twin]
696 for propagator2_1 in possible_propa_2:
697 fuse_list2_2=[propagator2_1.twin]
698 for propagator2_2 in propagator2_1.all_mother():
699 if propagator2_2 not in possible_propa_2 or propagator2_2.channel.startswith('T'):
700 break
701 propagator=[propagator1_1,propagator1_2,propagator2_1,propagator2_2]
702 fuse=[fuse_list1_1,fuse_list1_2,fuse_list2_1,fuse_list2_2]
703 sol+=self.define_new_ecs_d(propagator,fuse)
704
705 fuse_list2_2.append(propagator2_2.twin)
706 fuse_list2_1.append(propagator2_1.twin)
707 fuse_list1_2.append(propagator1_2.twin)
708 fuse_list1_1.append(propagator1_1.twin)
709
710 return sol
711
713 """ return a valid object for this change of variable """
714
715 for propa in propagator:
716 if propa.channel.startswith('T'):
717 return []
718
719 fuse_particle=[]
720 for data in fuse:
721 fuse_particle.append(self.define_fuse_region(data))
722 for particule in fuse_particle:
723 if particule.MG in [1,2]:
724 return []
725
726
727 New_sol=ECS_sector(self.MG_sec,'d',self.main_content,self.unaligned)
728 Block_ECS(New_sol,'d',self.main_content+fuse_particle)
729 New_sol.order_block(New_sol)
730 return [New_sol]
731