~madteam/mg5amcnlo/series2.0

« back to all changes in this revision

Viewing changes to madgraph/core/diagram_generation.py

  • Committer: olivier Mattelaer
  • Date: 2015-03-05 00:14:16 UTC
  • mfrom: (258.1.9 2.3)
  • mto: (258.8.1 2.3)
  • mto: This revision was merged to the branch mainline in revision 259.
  • Revision ID: olivier.mattelaer@uclouvain.be-20150305001416-y9mzeykfzwnl9t0j
partial merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
from madgraph import InvalidCmd
30
30
logger = logging.getLogger('madgraph.diagram_generation')
31
31
 
 
32
 
 
33
class NoDiagramException(InvalidCmd): pass
 
34
 
32
35
#===============================================================================
33
36
# DiagramTag mother class
34
37
#===============================================================================
59
62
        """Exception for any problems in DiagramTags"""
60
63
        pass
61
64
 
62
 
    def __init__(self, diagram, model = None, ninitial = 2):
 
65
    def __init__(self, diagram, model=None, ninitial=2):
63
66
        """Initialize with a diagram. Create DiagramTagChainLinks according to
64
67
        the diagram, and figure out if we need to shift the central vertex."""
65
68
 
138
141
    @classmethod
139
142
    def vertices_from_link(cls, link, model, first_vertex = False):
140
143
        """Recursively return the leg corresponding to this link and
141
 
        the list of all vertices from all previous links"""
 
144
        the list of all vertices from all previous links"""            
142
145
 
143
146
        if link.end_link:
144
147
            # This is an end link and doesn't correspond to a vertex
146
149
 
147
150
        # First recursively find all daughter legs and vertices
148
151
        leg_vertices = [cls.vertices_from_link(l, model) for l in link.links]
149
 
 
150
152
        # The daughter legs are in the first entry
151
153
        legs = base_objects.LegList(sorted([l for l,v in leg_vertices],
152
154
                                           lambda l1,l2: l2.get('number') - \
158
160
        if not first_vertex:
159
161
            # This corresponds to a wavefunction with a resulting leg
160
162
            # Need to create the resulting leg from legs and vertex id
161
 
            last_leg = cls.leg_from_legs(legs,
162
 
                                         cls.id_from_vertex_id(link.vertex_id),
163
 
                                         model)
 
163
            last_leg = cls.leg_from_legs(legs,link.vertex_id,model)
164
164
            legs.append(last_leg)
165
 
            
 
165
        
166
166
        # Now create and append this vertex
167
167
        vertices.append(cls.vertex_from_link(legs,
168
168
                                        link.vertex_id,
169
169
                                        model))
170
 
 
171
170
        if first_vertex:
172
171
            # Return list of vertices
173
172
            return vertices
175
174
            # Return leg and list of vertices
176
175
            return last_leg, vertices
177
176
 
178
 
    @staticmethod
179
 
    def leg_from_legs(legs, vertex_id, model):
 
177
    @classmethod
 
178
    def legPDGs_from_vertex_id(cls, vertex_id,model):
 
179
        """Returns the list of external PDGs of the interaction corresponding 
 
180
        to this vertex_id."""
 
181
        
 
182
        # In case we have to deal with a regular vertex, we return the list
 
183
        # external PDGs as given by the model information on that integer 
 
184
        # vertex id.
 
185
        if (len(vertex_id)>=3 and 'PDGs' in vertex_id[2]):
 
186
            return vertex_id[2]['PDGs']
 
187
        else:
 
188
            return [part.get_pdg_code() for part in model.get_interaction(
 
189
                             cls.id_from_vertex_id(vertex_id)).get('particles')]
 
190
 
 
191
    @classmethod
 
192
    def leg_from_legs(cls,legs, vertex_id, model):
180
193
        """Return a leg from a leg list and the model info"""
181
194
 
182
 
        pdgs = [part.get_pdg_code() for part in \
183
 
                model.get_interaction(vertex_id).get('particles')]
 
195
        pdgs = list(cls.legPDGs_from_vertex_id(vertex_id, model))
 
196
        
184
197
        # Extract the resulting pdg code from the interaction pdgs
185
198
        for pdg in [leg.get('id') for leg in legs]:
186
199
            pdgs.remove(pdg)
203
216
    def vertex_from_link(cls, legs, vertex_id, model):
204
217
        """Return a vertex given a leg list and a vertex id"""
205
218
 
206
 
        return base_objects.Vertex({'legs': legs,
207
 
                                    'id': cls.id_from_vertex_id(vertex_id)})
208
 
        
 
219
        vert_ID = cls.id_from_vertex_id(vertex_id)
 
220
        if vert_ID != -2:
 
221
            return base_objects.Vertex({'legs': legs,
 
222
                                        'id': vert_ID})
 
223
        else:
 
224
            contracted_vert = base_objects.ContractedVertex({'legs': legs,'id': -2})
 
225
            for key, value in cls.loop_info_from_vertex_id(vertex_id):
 
226
                if key in contracted_vert:
 
227
                    contracted_vert.set(key,value)    
 
228
 
209
229
    @staticmethod
210
230
    def leg_from_link(link):
211
231
        """Return a leg from a link"""
223
243
    @staticmethod
224
244
    def id_from_vertex_id(vertex_id):
225
245
        """Return the numerical vertex id from a link.vertex_id"""
226
 
        return vertex_id[0]
 
246
 
 
247
        return vertex_id[0][0]
 
248
    
 
249
    @staticmethod
 
250
    def loop_info_from_vertex_id(vertex_id):
 
251
        """Return the loop_info stored in this vertex id. Notice that the
 
252
        IdentifyME tag does not store the loop_info, but should normally never
 
253
        need access to it."""
 
254
 
 
255
        return vertex_id[2]
227
256
 
228
257
    @staticmethod
229
258
    def reorder_permutation(perm, start_perm):
252
281
        """Returns the default vertex id: just the interaction id
253
282
           Note that in the vertex id, like the leg, only the first entry is
254
283
           taken into account in the tag comparison, while the second is for 
255
 
           storing information that is not to be used in comparisons."""
 
284
           storing information that is not to be used in comparisons and the 
 
285
           third for additional info regarding the shrunk loop vertex."""
256
286
 
257
 
        return (vertex.get('id'),)
 
287
        if isinstance(vertex,base_objects.ContractedVertex):
 
288
#            return (vertex.get('id'),(),{'PDGs':vertex.get('PDGs')})
 
289
            return ((vertex.get('id'),vertex.get('loop_tag')),(),
 
290
                                                    {'PDGs':vertex.get('PDGs')})
 
291
        else:
 
292
            return ((vertex.get('id'),()),(),{})
258
293
 
259
294
    @staticmethod
260
295
    def flip_vertex(new_vertex, old_vertex, links):
506
541
        DiagramList by the function. This is controlled by the argument
507
542
        returndiag.
508
543
        """
 
544
 
509
545
        process = self.get('process')
510
546
        model = process.get('model')
511
547
        legs = process.get('legs')
534
570
                self['diagrams'] = res
535
571
                raise InvalidCmd, 'The number of fermion is odd'
536
572
            else:
537
 
                raise InvalidCmd, 'The number of fermion is odd'
538
 
 
 
573
                return False, res
539
574
 
540
575
        # Then check same number of incoming and outgoing fermions (if
541
576
        # no Majorana particles in model)
546
581
                self['diagrams'] = res
547
582
                raise InvalidCmd, 'The number of of incoming/outcoming fermions are different'
548
583
            else:
549
 
                raise InvalidCmd, 'The number of of incoming/outcoming fermions are different'
550
 
        
 
584
                return False, res
 
585
 
551
586
        # Finally check that charge (conserve by all interactions) of the process
552
587
        #is globally conserve for this process.
553
588
        for charge in model.get('conserved_charge'):
1660
1695
                        continue
1661
1696
 
1662
1697
                # Setup process
1663
 
                process = base_objects.Process({\
1664
 
                              'legs':legs,
1665
 
                              'model':process_definition.get('model'),
1666
 
                              'id': process_definition.get('id'),
1667
 
                              'orders': process_definition.get('orders'),
1668
 
                              'required_s_channels': \
1669
 
                                 process_definition.get('required_s_channels'),
1670
 
                              'forbidden_onsh_s_channels': \
1671
 
                                 process_definition.get('forbidden_onsh_s_channels'),
1672
 
                              'forbidden_s_channels': \
1673
 
                                 process_definition.get('forbidden_s_channels'),
1674
 
                              'forbidden_particles': \
1675
 
                                 process_definition.get('forbidden_particles'),
1676
 
                              'is_decay_chain': \
1677
 
                                 process_definition.get('is_decay_chain'),
1678
 
                              'perturbation_couplings': \
1679
 
                                 process_definition.get('perturbation_couplings'),
1680
 
                              'squared_orders': \
1681
 
                                 process_definition.get('squared_orders'),
1682
 
                              'sqorders_types': \
1683
 
                                 process_definition.get('sqorders_types'),                              
1684
 
                              'overall_orders': \
1685
 
                                 process_definition.get('overall_orders'),
1686
 
                              'has_born': \
1687
 
                                 process_definition.get('has_born'),
1688
 
                              'split_orders': \
1689
 
                                 process_definition.get('split_orders')                                
1690
 
                                 })
 
1698
                process = process_definition.get_process_with_legs(legs) 
 
1699
                
1691
1700
                fast_proc = \
1692
1701
                          array.array('i',[leg.get('id') for leg in legs])
1693
1702
                if collect_mirror_procs and \
1718
1727
                   not process.get('is_decay_chain'):
1719
1728
                    try:
1720
1729
                        crossed_index = success_procs.index(sorted_legs)
 
1730
                        # The relabeling of legs for loop amplitudes is cumbersome
 
1731
                        # and does not save so much time. It is disable here and
 
1732
                        # we use the key 'loop_diagrams' to decide whether
 
1733
                        # it is an instance of LoopAmplitude.
 
1734
                        if 'loop_diagrams' in amplitudes[crossed_index]:
 
1735
                            raise ValueError
1721
1736
                    except ValueError:
1722
1737
                        # No crossing found, just continue
1723
1738
                        pass
1759
1774
            if len(failed_procs) == 1 and 'error' in locals():
1760
1775
                raise error
1761
1776
            else:
1762
 
                raise InvalidCmd, \
 
1777
                raise NoDiagramException, \
1763
1778
            "No amplitudes generated from process %s. Please enter a valid process" % \
1764
1779
                  process_definition.nice_string()
1765
1780