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