29
29
from madgraph import InvalidCmd
30
30
logger = logging.getLogger('madgraph.diagram_generation')
33
class NoDiagramException(InvalidCmd): pass
32
35
#===============================================================================
33
36
# DiagramTag mother class
34
37
#===============================================================================
59
62
"""Exception for any problems in DiagramTags"""
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."""
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"""
143
146
if link.end_link:
144
147
# This is an end link and doesn't correspond to a vertex
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]
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
last_leg = cls.leg_from_legs(legs,link.vertex_id,model)
164
164
legs.append(last_leg)
166
166
# Now create and append this vertex
167
167
vertices.append(cls.vertex_from_link(legs,
172
171
# Return list of vertices
175
174
# Return leg and list of vertices
176
175
return last_leg, vertices
179
def leg_from_legs(legs, vertex_id, model):
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."""
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
185
if (len(vertex_id)>=3 and 'PDGs' in vertex_id[2]):
186
return vertex_id[2]['PDGs']
188
return [part.get_pdg_code() for part in model.get_interaction(
189
cls.id_from_vertex_id(vertex_id)).get('particles')]
192
def leg_from_legs(cls,legs, vertex_id, model):
180
193
"""Return a leg from a leg list and the model info"""
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))
184
197
# Extract the resulting pdg code from the interaction pdgs
185
198
for pdg in [leg.get('id') for leg in legs]:
203
216
def vertex_from_link(cls, legs, vertex_id, model):
204
217
"""Return a vertex given a leg list and a vertex id"""
206
return base_objects.Vertex({'legs': legs,
207
'id': cls.id_from_vertex_id(vertex_id)})
219
vert_ID = cls.id_from_vertex_id(vertex_id)
221
return base_objects.Vertex({'legs': legs,
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)
210
230
def leg_from_link(link):
211
231
"""Return a leg from a link"""
224
244
def id_from_vertex_id(vertex_id):
225
245
"""Return the numerical vertex id from a link.vertex_id"""
247
return vertex_id[0][0]
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."""
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."""
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')})
292
return ((vertex.get('id'),()),(),{})
260
295
def flip_vertex(new_vertex, old_vertex, links):
534
570
self['diagrams'] = res
535
571
raise InvalidCmd, 'The number of fermion is odd'
537
raise InvalidCmd, 'The number of fermion is odd'
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'
549
raise InvalidCmd, 'The number of of incoming/outcoming fermions are different'
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'):
1662
1697
# Setup process
1663
process = base_objects.Process({\
1665
'model':process_definition.get('model'),
1666
'id': process_definition.get('id'),
1667
'orders': process_definition.get('orders'),
1668
'NLO_mode': process_definition.get('NLO_mode'),
1669
'required_s_channels': \
1670
process_definition.get('required_s_channels'),
1671
'forbidden_onsh_s_channels': \
1672
process_definition.get('forbidden_onsh_s_channels'),
1673
'forbidden_s_channels': \
1674
process_definition.get('forbidden_s_channels'),
1675
'forbidden_particles': \
1676
process_definition.get('forbidden_particles'),
1678
process_definition.get('is_decay_chain'),
1679
'perturbation_couplings': \
1680
process_definition.get('perturbation_couplings'),
1682
process_definition.get('squared_orders'),
1684
process_definition.get('sqorders_types'),
1686
process_definition.get('overall_orders'),
1688
process_definition.get('has_born'),
1690
process_definition.get('split_orders')
1698
process = process_definition.get_process_with_legs(legs)
1693
1701
array.array('i',[leg.get('id') for leg in legs])
1694
1702
if collect_mirror_procs and \
1719
1727
not process.get('is_decay_chain'):
1721
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]:
1722
1736
except ValueError:
1723
1737
# No crossing found, just continue
1760
1774
if len(failed_procs) == 1 and 'error' in locals():
1777
raise NoDiagramException, \
1764
1778
"No amplitudes generated from process %s. Please enter a valid process" % \
1765
1779
process_definition.nice_string()