~amcblast/mg5amc-pineappl/trunk

« back to all changes in this revision

Viewing changes to madgraph/loop/loop_base_objects.py

  • Committer: marco zaro
  • Date: 2020-09-18 11:00:14 UTC
  • mfrom: (956.1.11 3.0.4)
  • Revision ID: marcozaro@pcteor1.mi.infn.it-20200918110014-5jc20pkwceijqspw
merged with 3.0.4 rev967

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
"""Definitions of all basic objects with extra features to treat loop 
17
17
   diagrams"""
18
18
 
 
19
from __future__ import absolute_import
19
20
import copy
20
21
import itertools
21
22
import logging
27
28
import madgraph.core.base_objects as base_objects
28
29
import madgraph.various.misc as misc
29
30
from madgraph import MadGraph5Error, MG5DIR
 
31
from six.moves import range
 
32
from six.moves import zip
30
33
 
31
34
logger = logging.getLogger('madgraph.loop_base_objects')
32
35
 
88
91
 
89
92
        if name == 'tag':
90
93
            if not isinstance(value, list):
91
 
                raise self.PhysicsObjectError, \
92
 
                        "%s is not a valid tag" % str(value)
 
94
                raise self.PhysicsObjectError("%s is not a valid tag" % str(value))
93
95
            else:
94
96
                for item in value:
95
97
                    if (len(item)!=3 or \
96
98
                      not isinstance(item[0],base_objects.Leg) or \
97
99
                      not isinstance(item[1],list)) or \
98
100
                      not isinstance(item[2],base_objects.Vertex):
99
 
                        raise self.PhysicsObjectError, \
100
 
                            "%s is not a valid tag" % str(value)
 
101
                        raise self.PhysicsObjectError("%s is not a valid tag" % str(value))
101
102
 
102
103
        if name == 'canonical_tag':
103
104
            if not isinstance(value, list):
104
 
                raise self.PhysicsObjectError, \
105
 
                        "%s is not a valid tag" % str(value)
 
105
                raise self.PhysicsObjectError("%s is not a valid tag" % str(value))
106
106
            else:
107
107
                for item in value:
108
108
                    if (len(item)!=3 or not isinstance(item[0],int) or \
109
109
                      not isinstance(item[1],list)) or \
110
110
                      not isinstance(item[2],int):
111
 
                        raise self.PhysicsObjectError, \
112
 
                            "%s is not a valid canonical_tag" % str(value)
 
111
                        raise self.PhysicsObjectError("%s is not a valid canonical_tag" % str(value))
113
112
 
114
113
        if name == 'CT_vertices':
115
114
            if not isinstance(value, base_objects.VertexList):
116
 
                raise self.PhysicsObjectError, \
117
 
                        "%s is not a valid VertexList object" % str(value)
 
115
                raise self.PhysicsObjectError("%s is not a valid VertexList object" % str(value))
118
116
 
119
117
        if name == 'type':
120
118
            if not isinstance(value, int):
121
 
                raise self.PhysicsObjectError, \
122
 
                        "%s is not a valid integer" % str(value)
 
119
                raise self.PhysicsObjectError("%s is not a valid integer" % str(value))
123
120
 
124
121
        if name == 'multiplier':
125
122
            if not isinstance(value, int):
126
 
                raise self.PhysicsObjectError, \
127
 
                        "%s is not a valid integer" % str(value)
 
123
                raise self.PhysicsObjectError("%s is not a valid integer" % str(value))
128
124
 
129
125
        if name == 'contracted_diagram':
130
126
            if not isinstance(value, base_objects.Diagram):
131
 
                raise self.PhysicsObjectError, \
132
 
                        "%s is not a valid Diagram." % str(value)                            
 
127
                raise self.PhysicsObjectError("%s is not a valid Diagram." % str(value))                            
133
128
 
134
129
        else:
135
130
            super(LoopDiagram, self).filter(name, value)
206
201
        # Without the tagging information we will have to reconstruct the
207
202
        # contracted diagrams with the unordered vertices
208
203
        if len(self.get('vertices'))==0:
209
 
            raise MadGraph5Error, "Function get_contracted_loop_diagram()"+\
 
204
            raise MadGraph5Error("Function get_contracted_loop_diagram()"+\
210
205
                "called for the first time without specifying struct_rep "+\
211
 
                                            "for a diagram already tagged."
 
206
                                            "for a diagram already tagged.")
212
207
                                
213
208
        # The leg below will be the outgoing one 
214
209
        contracted_vertex_last_loop_leg = None
354
349
 
355
350
        return tuple(
356
351
                 # For each loop vertex, we must identify the following three things
357
 
                 zip(
 
352
                 list(zip(
358
353
                   # Loop particle identification
359
354
                   loop_parts_tagging,
360
355
                   # FDStructure identification
361
356
                   FDStructs_tagging,
362
357
                   # Loop interactions identification
363
358
                   interactions_tagging,
364
 
                 )
 
359
                 ))
365
360
                 # Finally make sure that the loop orders are the same
366
361
                 + sorted(self.get_loop_orders(model).items())
367
362
               )
635
630
            start=start_in.get('number')
636
631
            end=end_in.get('number')
637
632
        else:
638
 
            raise MadGraph5Error, "In the diagram tag function, 'start' and "+\
639
 
                " 'end' must be either integers or Leg objects." 
 
633
            raise MadGraph5Error("In the diagram tag function, 'start' and "+\
 
634
                " 'end' must be either integers or Leg objects.") 
640
635
        
641
636
        if self.process_next_loop_leg(struct_rep,-1,-1,start,end,\
642
637
                                          loopVertexList, model, external_legs):
657
652
                canonical_tag=self.choose_optimal_lcut(self['tag'],struct_rep, 
658
653
                                                           model, external_legs)
659
654
            else:
660
 
                raise MadGraph5Error, 'The cutting method %s is not implemented.'\
661
 
                                                            %self.cutting_method
 
655
                raise MadGraph5Error('The cutting method %s is not implemented.'\
 
656
                                                            %self.cutting_method)
662
657
            # The tag of the diagram is now updated with the canonical tag
663
658
            self['tag']=canonical_tag
664
659
            # We assign here the loopVertexList to the list of vertices 
674
669
            self['canonical_tag']=[[t[0]['id'],t[1],t[2]] for t in canonical_tag]
675
670
            return True
676
671
        else:
677
 
            raise self.PhysicsObjectError, \
678
 
                  "Loop diagram tagging failed."
 
672
            raise self.PhysicsObjectError("Loop diagram tagging failed.")
679
673
            return False
680
674
 
681
675
 
688
682
        # Now we make sure we can combine those legs together (and 
689
683
        # obtain the output particle ID)
690
684
        key=tuple(sorted([leg.get('id') for leg in myleglist]))
691
 
        if ref_dict_to1.has_key(key):
 
685
        if key in ref_dict_to1:
692
686
            for interaction in ref_dict_to1[key]:
693
687
                # Find the interaction with the right ID
694
688
                if interaction[1]==vertID:
704
698
                    #    one initial state particle involved in the
705
699
                    #    combination -> t-channel
706
700
                    #    For a decay process there is of course no t-channel
707
 
                    if n_initial>1 and len(myleglist)>1 and len(filter( \
708
 
                        lambda leg: leg.get('state') == False, myleglist)) == 1:
 
701
                    if n_initial>1 and len(myleglist)>1 and len([leg for leg in myleglist if leg.get('state') == False]) == 1:
709
702
                        state = False
710
703
                    else:
711
704
                        state = True
717
710
                    # Now we can add the corresponding vertex
718
711
                    return base_objects.Vertex({'legs':myleglist,'id':vertID})
719
712
        else:
720
 
            raise cls.PhysicsObjectError, \
721
 
            "An interaction from the original L-cut diagram could"+\
722
 
            " not be found when reconstructing the loop vertices."
 
713
            raise cls.PhysicsObjectError("An interaction from the original L-cut diagram could"+\
 
714
            " not be found when reconstructing the loop vertices.")
723
715
 
724
716
    def process_next_loop_leg(self, structRep, fromVert, fromPos, currLeg, \
725
717
                                  endLeg, loopVertexList, model, external_legs):
748
740
                               self['vertices'][i].get('legs')[k],FDStruct)
749
741
 
750
742
            if not canonical:
751
 
                raise self.PhysicsObjectError, \
752
 
                      "Failed to reconstruct a FDStructure."
 
743
                raise self.PhysicsObjectError("Failed to reconstruct a FDStructure.")
753
744
            
754
745
            # The branch was directly an external leg, so it the canonical
755
746
            # repr of this struct is simply ((legID),0).
758
749
            elif isinstance(canonical,tuple):
759
750
                FDStruct.set('canonical',canonical)
760
751
            else:                                      
761
 
                raise self.PhysicsObjectError, \
762
 
                "Non-proper behavior of the construct_FDStructure function"
 
752
                raise self.PhysicsObjectError("Non-proper behavior of the construct_FDStructure function")
763
753
            
764
754
            # First check if this structure exists in the dictionary of the
765
755
            # structures already obtained in the diagrams for this process
792
782
        # == Code begins ==
793
783
        # We will scan the whole vertex list to look for the next loop
794
784
        # interaction.
795
 
        vertRange=range(len(self['vertices']))
 
785
        vertRange=list(range(len(self['vertices'])))
796
786
        # If we just start the iterative procedure, then from_vert=-1 and we
797
787
        # must look for the "start" loop leg in the entire vertices list
798
788
        if not fromVert == -1: 
815
805
            # it in the INPUTS of the vertices before. However, it it was an 
816
806
            # input of its vertex we must look in the OUTPUT of the vertices 
817
807
            # forehead
818
 
            legRange=range(len(self['vertices'][i].get('legs')))
 
808
            legRange=list(range(len(self['vertices'][i].get('legs'))))
819
809
            if fromPos == -1:
820
810
                # In the last vertex of the list, all entries are input
821
811
                if not i==len(self['vertices'])-1:
838
828
                        currLeg=base_objects.Leg(self['vertices'][i].get('legs')[j])
839
829
                        
840
830
                    # We can now process this loop interaction found...
841
 
                    for k in filter(lambda ind: not ind==j, \
842
 
                                   range(len(self['vertices'][i].get('legs')))):
 
831
                    for k in [ind for ind in range(len(self['vertices'][i].get('legs'))) if not ind==j]:
843
832
                        # ..for the structure k
844
833
                        # pos gives the direction in which to look for 
845
834
                        # nextLoopLeg from vertPos. It is after vertPos
858
847
                                nextLoopLeg=self['vertices'][i].get('legs')[k]
859
848
                                legPos=pos
860
849
                            else:
861
 
                                raise self.PhysicsObjectError, \
862
 
                                  " An interaction has more than two loop legs."
 
850
                                raise self.PhysicsObjectError(" An interaction has more than two loop legs.")
863
851
                        else:
864
852
                            process_loop_interaction(i,j,k,pos)
865
853
                    # Now that we have found loop leg curr_leg, we can get out 
1049
1037
        legPos=-2
1050
1038
        vertPos=-2
1051
1039
 
1052
 
        vertRange=range(len(self['vertices']))
 
1040
        vertRange=list(range(len(self['vertices'])))
1053
1041
 
1054
1042
        # Say we are at the beginning of the structure reconstruction algorithm 
1055
1043
        # of the structure above, with currLeg=1 so it was found in the vertex 
1135
1123
                branch=self.construct_FDStructure(i, legPos, \
1136
1124
                              self['vertices'][vertID].get('legs')[k], FDStruct)
1137
1125
                if not branch:
1138
 
                    raise self.PhysicsObjectError, \
1139
 
                          "Failed to reconstruct a FDStructure."
 
1126
                    raise self.PhysicsObjectError("Failed to reconstruct a FDStructure.")
1140
1127
                # That means that this branch was an external leg. 
1141
1128
                if isinstance(branch,int):
1142
1129
                    parentBuffer[0].append(branch)
1146
1133
                    parentBuffer[0]+=list(branch[0][0])
1147
1134
                    vertBuffer.append(branch)
1148
1135
                else:
1149
 
                    raise self.PhysicsObjectError, \
1150
 
                    "Non-proper behavior of the construct_FDStructure function"
 
1136
                    raise self.PhysicsObjectError("Non-proper behavior of the construct_FDStructure function")
1151
1137
            return legPos
1152
1138
 
1153
1139
        # == Beginning of the code ==
1159
1145
            # output of its vertices, then we must look in the inputs of 
1160
1146
            # these vertices. Remember that the last vertex of the list has only
1161
1147
            # inputs.
1162
 
            legRange=range(len(self['vertices'][i].get('legs')))
 
1148
            legRange=list(range(len(self['vertices'][i].get('legs'))))
1163
1149
            if fromPos == -1:
1164
1150
                # In the last vertex of the list, all entries are input
1165
1151
                if not i==len(self['vertices'])-1:
1193
1179
                FDStruct.get('external_legs').append(copy.copy(currLeg))
1194
1180
                return currLeg.get('number')
1195
1181
            else:
1196
 
                raise self.PhysicsObjectError, \
1197
 
                                  " A structure is malformed."
 
1182
                raise self.PhysicsObjectError(" A structure is malformed.")
1198
1183
        else:
1199
1184
            # In this case a vertex with currLeg has been found and we must
1200
1185
            # return the list of tuple described above. First let's sort the 
1263
1248
                                     in vertex['legs'] if leg['loop_line']])==2:
1264
1249
                vertex_orders = model.get_interaction(vertex['id'])['orders']
1265
1250
                for order in vertex_orders.keys():
1266
 
                    if order in loop_orders.keys():
 
1251
                    if order in list(loop_orders.keys()):
1267
1252
                        loop_orders[order]+=vertex_orders[order]
1268
1253
                    else:
1269
1254
                        loop_orders[order]=vertex_orders[order]
1360
1345
 
1361
1346
        if name == 'UVCT_couplings':
1362
1347
            if not isinstance(value, list):
1363
 
                raise self.PhysicsObjectError, \
1364
 
                        "%s is not a valid list" % str(value)
 
1348
                raise self.PhysicsObjectError("%s is not a valid list" % str(value))
1365
1349
            else:
1366
1350
                for elem in value:
1367
1351
                    if not isinstance(elem, str) and not isinstance(elem, int):
1368
 
                        raise self.PhysicsObjectError, \
1369
 
                        "%s is not a valid string" % str(value)
 
1352
                        raise self.PhysicsObjectError("%s is not a valid string" % str(value))
1370
1353
        
1371
1354
        if name == 'UVCT_orders':
1372
1355
            if not isinstance(value, dict):
1373
 
                raise self.PhysicsObjectError, \
1374
 
                        "%s is not a valid dictionary" % str(value)
 
1356
                raise self.PhysicsObjectError("%s is not a valid dictionary" % str(value))
1375
1357
 
1376
1358
        if name == 'type':
1377
1359
            if not isinstance(value, str):
1378
 
                raise self.PhysicsObjectError, \
1379
 
                        "%s is not a valid string" % str(value)
 
1360
                raise self.PhysicsObjectError("%s is not a valid string" % str(value))
1380
1361
        
1381
1362
        else:
1382
1363
            super(LoopUVCTDiagram, self).filter(name, value)
1445
1426
        if len(args)>0 and isinstance(args[0],LoopModel):
1446
1427
            if hasattr(args[0],'map_CTcoup_CTparam'):
1447
1428
                self.map_CTcoup_CTparam = copy.copy(args[0].map_CTcoup_CTparam)
 
1429
            if hasattr(args[0],'notused_ct_params'):
 
1430
                self.notused_ct_params = list(args[0].notused_ct_params)                
1448
1431
 
1449
1432
        super(LoopModel,self).__init__(*args,**opts)
1450
1433
 
1474
1457
 
1475
1458
        if name == 'perturbation_couplings':
1476
1459
            if not isinstance(value, list):
1477
 
                raise self.PhysicsObjectError, \
1478
 
                    "Object of type %s is not a list" % \
1479
 
                                                            type(value)
 
1460
                raise self.PhysicsObjectError("Object of type %s is not a list" % \
 
1461
                                                            type(value))
1480
1462
            for order in value:
1481
1463
                if not isinstance(order, str):
1482
 
                    raise self.PhysicsObjectError, \
1483
 
                        "Object of type %s is not a string" % \
1484
 
                                                            type(order)
 
1464
                    raise self.PhysicsObjectError("Object of type %s is not a string" % \
 
1465
                                                            type(order))
1485
1466
        else:
1486
1467
            super(LoopModel,self).filter(name,value)
1487
1468
        
1534
1515
 
1535
1516
        if name == 'depth':
1536
1517
            if not isinstance(value, int):
1537
 
                raise self.PhysicsObjectError, \
1538
 
                    "Object of type %s is not a int" % \
1539
 
                                                            type(value)
 
1518
                raise self.PhysicsObjectError("Object of type %s is not a int" % \
 
1519
                                                            type(value))
1540
1520
        else:
1541
1521
            super(DGLoopLeg,self).filter(name,value)
1542
1522
        
1545
1525
    def get_sorted_keys(self):
1546
1526
        """Return process property names as a nicely sorted list."""
1547
1527
 
1548
 
        return ['id', 'number', 'state', 'from_group','loop_line','depth']
 
1528
        return ['id', 'number', 'state', 'from_group','loop_line','depth', 
 
1529
                'polarization']
1549
1530
    
1550
1531
    def convert_to_leg(self):
1551
1532
        """ Converts a DGLoopLeg back to a Leg. Basically removes the extra
1555
1536
        for key in aleg.get_sorted_keys():
1556
1537
            aleg.set(key,self[key])
1557
1538
 
 
1539
 
1558
1540
        return aleg
1559
1541
 
1560
1542
#===============================================================================
1587
1569
 
1588
1570
        if name == 'vertices':
1589
1571
            if not isinstance(value, base_objects.VertexList):
1590
 
                raise self.PhysicsObjectError, \
1591
 
        "%s is not a valid VertexList object" % str(value)
 
1572
                raise self.PhysicsObjectError("%s is not a valid VertexList object" % str(value))
1592
1573
 
1593
1574
        if name == 'id':
1594
1575
            if not isinstance(value, int):
1595
 
                raise self.PhysicsObjectError, \
1596
 
        "id %s is not an integer" % repr(value)
 
1576
                raise self.PhysicsObjectError("id %s is not an integer" % repr(value))
1597
1577
 
1598
1578
        if name == 'weight':
1599
1579
            if not isinstance(value, int):
1600
 
                raise self.PhysicsObjectError, \
1601
 
        "weight %s is not an integer" % repr(value)
 
1580
                raise self.PhysicsObjectError("weight %s is not an integer" % repr(value))
1602
1581
 
1603
1582
        if name == 'external_legs':
1604
1583
            if not isinstance(value, base_objects.LegList):
1605
 
                raise self.PhysicsObjectError, \
1606
 
        "external_legs %s is not a valid Leg List" % str(value)
 
1584
                raise self.PhysicsObjectError("external_legs %s is not a valid Leg List" % str(value))
1607
1585
 
1608
1586
        if name == 'binding_leg':
1609
1587
            if not isinstance(value, base_objects.Leg):
1610
 
                raise self.PhysicsObjectError, \
1611
 
        "binding_leg %s is not a valid Leg" % str(value)
 
1588
                raise self.PhysicsObjectError("binding_leg %s is not a valid Leg" % str(value))
1612
1589
 
1613
1590
        if name == 'canonical':
1614
1591
            if not isinstance(value, tuple):
1615
 
                raise self.PhysicsObjectError, \
1616
 
        "canonical %s is not a valid tuple" % str(value)
 
1592
                raise self.PhysicsObjectError("canonical %s is not a valid tuple" % str(value))
1617
1593
 
1618
1594
        return True
1619
1595
    
1693
1669
        ref_dict_to1 = model.get('ref_dict_to1')
1694
1670
 
1695
1671
        if not tag:
1696
 
            raise self.PhysicsObjectError, \
1697
 
        "The canonical tag of the FD structure is not set yet, so that the "+\
1698
 
        "reconstruction of the vertices cannot be performed."
 
1672
            raise self.PhysicsObjectError("The canonical tag of the FD structure is not set yet, so that the "+\
 
1673
        "reconstruction of the vertices cannot be performed.")
1699
1674
 
1700
1675
        # Create a local copy of the external legs
1701
1676
        leglist = copy.deepcopy(external_legs)
1734
1709
 
1735
1710
            # Now we make sure we can combine those legs together
1736
1711
            key=tuple(sorted([leg.get('id') for leg in legs]))
1737
 
            if ref_dict_to1.has_key(key):
 
1712
            if key in ref_dict_to1:
1738
1713
                for interaction in ref_dict_to1[key]:
1739
1714
                    # Find the interaction with the right ID
1740
1715
                    if interaction[1]==tag[0][1]:
1746
1721
                        number = min([leg.get('number') for leg in legs])
1747
1722
                        # 3) state is final, unless there is exactly one initial 
1748
1723
                        # state particle involved in the combination -> t-channel
1749
 
                        if len(filter(lambda leg: leg.get('state') == False,
1750
 
                                  legs)) == 1:
 
1724
                        if len([leg for leg in legs if leg.get('state') == False]) == 1:
1751
1725
                            state = False
1752
1726
                        else:
1753
1727
                            state = True
1783
1757
                tag.pop(0)
1784
1758
 
1785
1759
            else:
1786
 
                raise self.PhysicsObjectError, \
1787
 
        "The canonical tag of the FD structure is corrupted because one "+\
1788
 
        "interaction does not exist."
 
1760
                raise self.PhysicsObjectError("The canonical tag of the FD structure is corrupted because one "+\
 
1761
        "interaction does not exist.")
1789
1762
 
1790
1763
#===============================================================================
1791
1764
# FDStructureList
1814
1787
                    return FDStruct
1815
1788
            return None
1816
1789
        else:
1817
 
            raise self.PhysicsObjectListError, \
1818
 
              "The ID %s specified for get_struct is not an integer or tuple"%\
1819
 
                                                                    repr(object)
 
1790
            raise self.PhysicsObjectListError("The ID %s specified for get_struct is not an integer or tuple"%\
 
1791
                                                                    repr(object))
1820
1792
 
1821
1793
    def nice_string(self):
1822
1794
        """Returns a nicely formatted string"""