Package madgraph :: Package madweight :: Module substructure_class
[hide private]
[frames] | no frames]

Source Code for Module madgraph.madweight.substructure_class

  1  #!/usr/bin/env python 
  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   
19 -class diagram:
20
21 - def __init__(self):
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
46 - def define_neut_content(self):
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
55 - def define_level(self):
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 #level of a propagator 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 #print propa.MG, propa.level 70 #level of initial particle 71 self.content[1].level=0 72 self.content[2].level=0 73 #level of an external particle 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
81 - def order_in_level(self):
82 "return list with external particle ordering following level" 83 84 #organise in level in a dictionary 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 #re-organise like a list 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 #note that content is a dict or list depending of the object 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
117 -class ECS_sector_no_multi_channel(diagram,Level_generation):
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}#number of particles used to restore E-p conservation 129 130 #initialization 131 diagram.__init__(self) 132 Level_generation.__init__(self,'ecs') 133 self.fuse=0 134 #store initial input 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 #construct more elaborate things 143 self.num_neut=neut_in_class[chgt_var] 144 self.intrinsec=intrinsec_in_class[chgt_var] #number of particles used to restore E-p conservation 145 self.opt=diag.opt
146
147 - def define_blob(self,diag,propa_in_ecs=""):
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 #define blob from the black box 156 157 158 #define all the mother of the one/two central particle of the ecs 159 for i in range(0,self.intrinsec): 160 161 #define a list of combine all mother 162 if i==0: 163 combine_all_mother=[] 164 combine_all_mother+=propa_in_ecs[i].all_mother() #not in one line (we doesn't want to have a pointer) 165 continue 166 #i>0 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 #define blob 172 for particle in combine_all_mother: 173 #print 'mother',particle.MG, len(combine_all_mother) 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 #This technique is not complete for 'T' channel. In this case some branch are simply forget. 179 #add those branch 180 for i in range(-1*diag.num_propa,0): 181 propa=diag.content[i] 182 #first look at T Channel 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 #at this point particle is propagator 189 elif(desint not in combine_all_mother): 190 blob_sector(desint,diag,ECS_sec=self) 191 #This technique fails for the 'free' branch => look at particle without mother 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
199 - def equivalent_ECS(self):
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 #option: authorize a! 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 #option: authorize b or c! 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 #two neutrino case 221 #option: authorize d or e or f! 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
230 - def equivalent_ECS_1neut(self,use_noresonant=0):
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 # 1.1) ->search for the two thiner propagator+ check if we can pass in C change of variable 236 thiner=self.main_content[0].mother.width 237 part_thin=self.main_content[0].mother 238 thiner_bef_m0=500 #thiner propagator in ascendance of mass nul (for Case C) 239 thiner_m0=500 #thiner mother of a mass null particle (for Case C) 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 #check for C splitting: 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 #1.2) ->create block and new ECS first for C change of variable secondly for B 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 # define B change of variable 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 #2) Check definition from option 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
303 - def equivalent_ECS_2neut(self):
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 # Enlarged constraint Sector D 313 # 314 if self.chgt_var=='d': 315 #check validity from option 316 if not self.opt.use_ecs_d: 317 return [] 318 #find the two thiner propagator for each neutrino 319 for i in [0,1]: 320 thiner=500 321 thiner2=600 322 #search thiner propa if option authorized 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 #check number of find solution and reassign 333 if thiner==500: #no propagator in S channel or don't use fuse 334 thiner=self.main_content[i].mother.width #order between thiner 335 thiner2=self.main_content[i].mother.mother.width #is irrelevant at this stage 336 if thiner2==500: #only one propagator in S channel 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 #define fuse particle 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 # Enlarged constraint Sector E 363 # 364 elif self.chgt_var=='e': 365 #check validity from option 366 if not self.opt.use_ecs_e: 367 return [] 368 #find the two thiner propagator 369 for i in [0,1]: 370 #search thiner propagator if option authorized 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 #define fuse particle 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 #print 'ECS E content: ', 393 #for particle in self.main_content+fuse_particle:#a.order_content: 394 # print particle.MG, 395 #print 396 return [self] 397 # 398 # Enlarged constraint Sector F 399 # 400 elif self.chgt_var=='f' or self.chgt_var=='g': 401 #check validity from option 402 if not self.opt.use_ecs_f: 403 return [] 404 #F change of variable can't have freedom to move those propagator 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 #control of flux 421 for neutrino in self.main_content: 422 motherX=neutrino 423 #treat first zero neutrino case: ->particle following 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 #treat all case ->particle before main 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
453 - def order_block(self,main_sec=''):
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 #print block 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
477 - def info(self):
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
505 - def __str__(self):
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
525 -class blob_sector(diagram):
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 #Check if already defined + validity of the definition of a blob 532 if particle.MG in diag.blob_content: # check if the blob is already defined 533 self=diag.blob_content[particle.MG] 534 self.put_in_ecs(ECS_sec) 535 return #stop creation 536 elif particle.MG in range(0,diag.num_init):#remove initial particle from creating blob 537 return None 538 elif not particle.external: 539 if not particle.channel.startswith('S'): #remove T channel from creating a blob 540 return None 541 542 #creation of a new blob 543 diagram.__init__(self) 544 #put the main_diag up-to-date 545 diag.blob_content[particle.MG]=self 546 #put the ECS up-to-date 547 self.put_in_ecs(ECS_sec) 548 #put information in the blob 549 self.main=particle 550 self.generate_content() 551 self.solution=[] 552 #option 553 self.opt=diag.opt
554 555
556 - def put_in_ecs(self,ECS_sec):
557 """ put this blob in the blob content of ECS """ 558 #option put in ECS-blob content ->remark the blob is independant of the ECS 559 if ECS_sec: 560 if self not in ECS_sec.blob_content: 561 ECS_sec.blob_content.append(self)
562
563 - def generate_content(self):
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 #order in propa is not good ->change it? 579
580 - def find_solutions(self):
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
602 - def __str__(self):
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
609 -class ECS_sector(ECS_sector_no_multi_channel):
610 """ modify version of ECS sector, returning the different 611 possibility of unalignment in the black box 612 (usefull for multichannel mode) 613 """ 614
615 - def equivalent_ECS_1neut(self,use_noresonant=0):
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] #define the blob fuse 624 for propagator in self.main_content[0].all_mother(): 625 if propagator.channel.startswith('T'): 626 break 627 # define a B change of variable 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 #look for class C 636 if self.opt.use_ecs_c: 637 sol+=self.equivalent_ECS_passinC(propagator,fuse_list) 638 639 #update fuse for next level 640 fuse_list.append(propagator.twin) 641 642 643 return sol
644 645
646 - def equivalent_ECS_passinC(self,propa1,fuse1):
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 [] #the mass should be 0 655 if particle2.MG<3: 656 return [] 657 propa2=propa1.mother 658 if propa2 == 0 or propa2.channel.startswith('T'): 659 return [] #not enough propa remaining 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
668 - def equivalent_ECS_2neut(self):
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] #define the blob fuse 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] #define the blob fuse 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
712 - def define_new_ecs_d(self,propagator,fuse):
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