1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Definitions of the objects needed both for MadFKS from real
17 and MadFKS from born"""
18
19 import madgraph.core.base_objects as MG
20 import madgraph.core.helas_objects as helas_objects
21 import madgraph.core.diagram_generation as diagram_generation
22 import madgraph.core.color_amp as color_amp
23 import madgraph.core.color_algebra as color_algebra
24 from operator import itemgetter
25 import copy
26 import logging
27 import array
28 import fractions
29 import madgraph.various.misc as misc
34 """Exception for MadFKS"""
35 pass
36
39 """Modified diagram tags to be used to link born and real configurations.
40 """
41
42 @staticmethod
44 """Returns the default end link for a leg: ((id, number), number).
45 Note that the number is not taken into account if tag comparison,
46 but is used only to extract leg permutations.
47 """
48 return [((leg.get('id'), leg.get('number')), leg.get('number'))]
49
52 """computes the QED/QCD orders from the knowledge of the n of ext particles
53 and of the weighted orders"""
54
55
56 QED = weighted - nexternal + 2
57 QCD = weighted - 2 * QED
58 return QED, QCD
59
62 """finds the real configurations that match the born ones, i.e. for
63 each born configuration, the real configuration that has the ij ->
64 i j splitting. i, j and ij are integers, and refer to the leg
65 position in the real process (i, j) and in the born process (ij).
66 """
67
68 id_ij = born_amp['process']['legs'][ij - 1]['id']
69 nlegs_b = len(born_amp['process']['legs'])
70 nlegs_r = len(real_amp['process']['legs'])
71 if nlegs_r - nlegs_b != 1:
72 raise FKSProcessError('Inconsistent number of born and real legs: %d %d' % (nlegs_b, nlegs_r))
73
74
75 shift_dict = {}
76 for ir in range(1, nlegs_r + 1):
77 shift = 0
78 if ir > j:
79 shift += 1
80 if ir > i:
81 shift += 1
82 if ir > ij and ij <= max(i,j):
83 shift -= 1
84 shift_dict[ir] = ir - shift
85
86
87 minvert = min([max([len(vert.get('legs')) \
88 for vert in diag.get('vertices')]) \
89 for diag in born_amp.get('diagrams')])
90
91 born_confs = []
92 real_confs = []
93
94 k=0
95 for diag in born_amp.get('diagrams'):
96 if any([len(vert.get('legs')) > minvert for vert in
97 diag.get('vertices')]):
98 continue
99 else:
100 born_confs.append({'number' : k, 'diagram' : diag})
101 k=k+1
102
103 k=0
104 for diag in real_amp.get('diagrams'):
105 if any([len(vert.get('legs')) > minvert \
106 for vert in diag.get('vertices')]):
107 continue
108 else:
109 real_confs.append({'number': k, 'diagram': diag})
110 k=k+1
111
112 good_diags = []
113
114
115
116
117 real_confs_new = copy.deepcopy(real_confs)
118 for diag in real_confs_new:
119 for vert in diag['diagram'].get('vertices'):
120 vert_legs = [l.get('number') for l in vert.get('legs')]
121 vert_ids = [l.get('id') for l in vert.get('legs')]
122 if (i in vert_legs and not j in vert_legs) or \
123 (j in vert_legs and not i in vert_legs):
124 break
125
126 if i in vert_legs and j in vert_legs:
127 vert_ids.remove(vert_ids[vert_legs.index(i)])
128 vert_legs.remove(i)
129 vert_ids.remove(vert_ids[vert_legs.index(j)])
130 vert_legs.remove(j)
131 last_leg = vert_legs[0]
132
133
134 if abs(vert_ids[0]) == abs(id_ij):
135 diag['diagram']['vertices'].remove(vert)
136 good_diags.append({'diagram': diag['diagram'],
137 'leg_ij': last_leg,
138 'number': diag['number']})
139 break
140
141
142
143
144
145
146
147
148
149
150
151 for ir in range(1, nlegs_r + 1):
152 for good_diag in good_diags:
153 for vert in good_diag['diagram'].get('vertices'):
154 for l in vert.get('legs'):
155 if l.get('number') == ir:
156 l.set('number', shift_dict[l.get('number')])
157
158
159 if len(good_diags) == 1 and len(born_confs) == 1:
160 return [{'real_conf': good_diags[0]['number'],
161 'born_conf': born_confs[0]['number']}]
162
163
164
165 if nlegs_b ==3:
166 for diag in good_diags:
167 counts = []
168 for il in range(nlegs_b):
169 counts.append([l['number'] for v in diag['diagram']['vertices'] for l in v['legs']].count(il+1))
170
171
172 even_list = [c / 2 * 2 == c for c in counts]
173 if any(even_list):
174 if not even_list.count(True) == 2:
175 raise FKSProcessError('Linking: Don\'t know what to do in this case')
176
177 ilmax = counts.index(max([c for c in counts if even_list[counts.index(c)]]))
178 ilmin = counts.index(min([c for c in counts if even_list[counts.index(c)]]))
179
180
181 replaced = False
182 for vert in diag['diagram']['vertices']:
183 for leg in vert['legs']:
184 if leg['number'] == ilmax + 1 and not replaced:
185 leg['number'] = ilmin + 1
186 replaced = True
187
188
189 born_tags = [FKSDiagramTag(d['diagram'],
190 born_amp.get('process').get('model')) \
191 for d in born_confs]
192
193
194 real_tags = [FKSDiagramTag(d['diagram'],
195 real_amp.get('process').get('model')) \
196 for d in good_diags ]
197 real_tags = []
198 for d in good_diags:
199 tag = FKSDiagramTag(d['diagram'], real_amp.get('process').get('model'))
200 if not tag in real_tags:
201 real_tags.append(tag)
202
203
204 if len(born_tags) != len(real_tags):
205 print '\n'.join([str(r) for r in real_tags]) + '\n'
206 raise FKSProcessError('Cannot map born/real configurations between \
207 %s and %s (i,j=%d,%d): not same number of configurations: %d %d' % \
208 (born_amp.get('process').nice_string().replace('Process:',''),
209 real_amp.get('process').nice_string().replace('Process:',''),
210 i,j,
211 len(born_tags),
212 len(real_tags)))
213
214 links = []
215 for ib, btag in enumerate(born_tags):
216 try:
217 ir = real_tags.index(btag)
218 links.append({'real_conf': good_diags[ir]['number'],
219 'born_conf': born_confs[ib]['number']})
220 real_tags.remove(btag)
221 good_diags.pop(ir)
222 except ValueError:
223 print real_tags, i, j, ij
224 print '\n'.join( d['diagram'].nice_string() for d in good_diags)
225 raise FKSProcessError('Linking %s to %s: could not link born diagram %s' % \
226 (born_amp.get('process').nice_string().replace('Process:',''),
227 real_amp.get('process').nice_string().replace('Process:',''),
228 born_confs[ib]['diagram'].nice_string()) )
229
230 return links
231
235 """Takes an amplitude as input, and returns a dictionary with the
236 orders of the couplings.
237 """
238 assert isinstance(amp, diagram_generation.Amplitude)
239 orders = {}
240 for diag in amp.get('diagrams'):
241 for order, value in diag.get('orders').items():
242 if value != 0 or order in amp['process']['orders'].keys():
243 try:
244 orders[order] = max(orders[order], value)
245 except KeyError:
246 orders[order] = value
247 return orders
248
249
250 -def find_splittings(leg, model, dict, pert='QCD', include_init_leptons=True):
251 """Finds the possible splittings corresponding to leg
252 """
253
254 leptons = model.get_lepton_pdgs()
255
256 if dict == {}:
257 dict = find_pert_particles_interactions(model, pert)
258 splittings = []
259
260
261 if leg.get('id') in dict['pert_particles']:
262 part = model.get('particle_dict')[leg.get('id')]
263 antipart = model.get('particle_dict')[part.get_anti_pdg_code()]
264 for ii in dict['interactions']:
265
266 parts = copy.deepcopy(ii['particles'])
267 nsoft = 0
268 if part in parts:
269
270
271 try:
272 parts.pop(parts.index(antipart))
273 except ValueError:
274 parts.pop(parts.index(part))
275 for p in parts:
276 if p.get_pdg_code() in dict['soft_particles']:
277 nsoft += 1
278 if nsoft >= 1:
279 for split in split_leg(leg, parts, model):
280
281
282
283 if include_init_leptons or \
284 not (any([l['id'] in leptons for l in split if not l['state']])):
285 splittings.append(split)
286 return splittings
287
288
289 -def find_mothers(leg1, leg2, model, dict={}, pert='', mom_mass=''):
290 """Find the possible mothers of leg1, leg2.
291 If mom_mass is passed, only the mothers with mom_mass are returned
292 """
293 if pert:
294 if dict == {}:
295 dict = find_pert_particles_interactions(model, pert)
296 interactions = dict['interactions']
297 mothers = []
298
299 for inte in interactions:
300
301
302 pdgs = [p.get_pdg_code() for p in inte['particles']]
303 try:
304 for l in [leg1, leg2]:
305 if not l['state']:
306 pdgs.remove(l['id'])
307 else:
308 pdgs.remove(model.get('particle_dict')[l['id']].get_anti_pdg_code())
309 except ValueError:
310 continue
311 if mom_mass and \
312 mom_mass.lower() == model.get('particle_dict')[pdgs[0]]['mass'].lower():
313 mothers.append(pdgs[0])
314
315 return mothers
316
319 """Splits the leg into parts, and returns the two new legs.
320 """
321
322 split = []
323
324 if leg['state'] :
325 split.append([])
326 for part in parts:
327 split[-1].append(to_fks_leg({'state': True, \
328 'id': part.get_pdg_code()},model))
329 ij_final(split[-1])
330
331
332 else:
333 if parts[0] != parts[1]:
334 for part in parts:
335 cparts = copy.deepcopy(parts)
336 split.append([\
337 to_fks_leg({'state': False,
338 'id': cparts.pop(cparts.index(part)).get_pdg_code(),
339 'fks': 'j'}, model),
340 to_fks_leg({'state': True,
341 'id': cparts[0].get_anti_pdg_code(),
342 'fks': 'i'}, model)\
343 ])
344 else:
345 split.append([\
346 to_fks_leg({'state': False,
347 'id': parts[0].get_pdg_code(),
348 'fks': 'j'}, model),
349 to_fks_leg({'state': True,
350 'id': parts[1].get_anti_pdg_code(),
351 'fks': 'i'}, model)])
352 return split
353
356 """given a pair of legs in the final state, assigns the i/j fks id
357 NOTE: the j partons is always put before the i one
358 """
359
360
361
362 if len(pair) == 2:
363 for i in range(len(pair)):
364 set = 0
365 if (pair[i]['massless'] and pair[i]['self_antipart']) or \
366 (not pair[i]['is_part'] and pair[1-i]['is_part'] and\
367 (pair[i]['spin']+pair[1-i]['spin'])%2==0) and not set:
368 pair[i]['fks'] = 'i'
369 pair[1-i]['fks'] = 'j'
370
371 if i < 1 - i:
372 pair.reverse()
373 set = 1
374
376 """Returns a new leglist with leg splitted into split.
377 The convention is to remove leg ij, replace it with leg j, and put
378 i at the end of the group of legs with the same color(charge) representation
379 """
380 if pert =='QCD':
381 color = 'color'
382 elif pert == 'QED':
383 color = 'charge'
384 else:
385 raise FKSProcessError, "Only QCD or QED is allowed not %s" % pert
386
387 leglist = FKSLegList(copy.deepcopy(leglist_orig))
388
389 for i in range(len(leglist)):
390 if leglist[-i - 1].get('state'):
391 firstfinal = len(leglist) - i - 1
392
393 leglist[leglist.index(leg)] = split[0]
394
395 col_maxindex = {}
396 mass_col_maxindex = {}
397 for col in set([l[color] for l in leglist[firstfinal:] if l['massless']]):
398 col_maxindex[col] = max([0] + [leglist.index(l) for l in leglist[firstfinal:]\
399 if l[color] == col and l['massless']])
400 for col in set([abs(l[color]) for l in leglist[firstfinal:] if not l['massless']]):
401 mass_col_maxindex[col] = max([0] + [leglist.index(l) for l in leglist[firstfinal:]\
402 if abs(l[color]) == col and not l['massless']])
403
404 if pert == 'QCD':
405 for col in copy.copy(col_maxindex.keys()):
406 if abs(col) > abs(split[1][color]):
407 del col_maxindex[col]
408
409
410
411
412 if split[1]['is_part'] and not split[1]['self_antipart']:
413
414
415
416
417 try:
418 del col_maxindex[-split[1][color]]
419 except KeyError:
420 pass
421
422 leglist.insert(max(col_maxindex.values() + mass_col_maxindex.values() + [firstfinal - 1] ) + 1, split[1])
423
424
425
426
427
428
429
430
431
432
433
434 for i, leg in enumerate(leglist):
435 leg['number'] = i + 1
436 return leglist
437
438
439 -def combine_ij( i, j, model, dict, pert='QCD'):
440 """checks whether FKSlegs i and j can be combined together in the given model
441 and with given perturbation order and if so combines them into ij.
442 If dict is empty it is initialized with find_pert_particles_interactions
443 """
444 if dict == {}:
445 dict = find_pert_particles_interactions(model, pert)
446 ij = []
447 num = copy.copy(min(i.get('number'), j.get('number')))
448
449
450 not_double_counting = (j.get('spin') == 3 and j.get('massless') and
451 i.get('spin') == 3 and i.get('massless')) or \
452 j.get('spin') != 3 or not j.get('massless') or \
453 not j.get('state')
454
455
456
457 if j.get('state') and j.get('id') == - i.get('id'):
458 not_double_counting = not_double_counting and j.get('id') >0
459
460 if i.get('id') in dict['soft_particles'] and \
461 j.get('id') in dict['pert_particles'] and \
462 i.get('state') and not_double_counting:
463 for int in dict['interactions']:
464 parts= copy.copy(int['particles'])
465
466 try:
467 parts.remove(model.get('particle_dict')[i.get('id')])
468 except ValueError:
469 continue
470
471
472 if j.get('state'):
473 j_id = j.get('id')
474 else:
475 j_id = model.get('particle_dict')[j.get('id')].get_anti_pdg_code()
476 try:
477 parts.remove(model.get('particle_dict')[j_id])
478 except ValueError:
479 continue
480
481
482 if j.get('state'):
483 ij.append(MG.Leg({
484 'id': parts[0].get_anti_pdg_code(),
485 'state': True,
486 'number': num}))
487 else:
488 ij.append(MG.Leg({
489 'id': parts[0].get_pdg_code(),
490 'state': False,
491 'number': num}))
492 return to_fks_legs(ij, model)
493
494
495 -def find_pert_particles_interactions(model, pert_order = 'QCD'):
496 """given a model and pert_order, returns a dictionary with as entries:
497 --interactions : the interactions of order pert_order
498 --pert_particles : pdgs of particles taking part to interactions
499 --soft_particles : pdgs of massless particles in pert_particles
500 """
501
502 ghost_list = []
503 ghost_list += [ p.get_pdg_code() for p in model.get('particles')
504 if p.get('ghost') or p.get('goldstone')]
505
506 qcd_inter = MG.InteractionList()
507 pert_parts = []
508 soft_parts = []
509 for i, ii in model.get('interaction_dict').items():
510
511
512 if ii.get('orders') == {pert_order:1} and len(ii['particles']) == 3 :
513 masslist = [p.get('mass').lower() for p in ii['particles']]
514
515
516
517
518 try:
519 masslist.remove('zero')
520 except ValueError:
521 continue
522 if len(set(masslist)) == 1 and not \
523 any( [ p.get_pdg_code() in ghost_list or \
524 p.get_anti_pdg_code() in ghost_list for p in ii['particles']]) :
525 qcd_inter.append(ii)
526 for pp in ii['particles']:
527 pert_parts.append(pp.get_pdg_code())
528 if pp['mass'].lower() == 'zero':
529 soft_parts.append(pp.get_pdg_code())
530
531 return {'interactions': sorted(qcd_inter),
532 'pert_particles': sorted(set(pert_parts)),
533 'soft_particles': sorted(set(soft_parts))}
534
537 """insert the color links in col_obj: returns a list of dictionaries
538 (one for each link) with the following entries:
539 --link: the numbers of the linked legs
540 --link_basis: the linked color basis
541 --link_matrix: the color matrix created from the original basis and the linked one
542 """
543 assert isinstance(col_basis, color_amp.ColorBasis)
544 assert isinstance(col_obj, list)
545 result =[]
546 for link in links:
547 this = {}
548
549 l =[]
550 for leg in link['legs']:
551 l.append(leg.get('number'))
552 this['link'] = l
553
554
555
556
557
558 this_col_obj = []
559 for old_dict in col_obj:
560 new_dict = dict(old_dict)
561 for k, string in new_dict.items():
562 new_dict[k] = string.create_copy()
563 for col in new_dict[k]:
564 for ind in col:
565 for pair in link['replacements']:
566 if ind == pair[0]:
567 col[col.index(ind)] = pair[1]
568 new_dict[k].product(link['string'])
569 this_col_obj.append(new_dict)
570 basis_link = color_amp.ColorBasis()
571 for ind, new_dict in enumerate(this_col_obj):
572 basis_link.update_color_basis(new_dict, ind)
573
574 this['link_basis'] = basis_link
575 this['link_matrix'] = color_amp.ColorMatrix(col_basis,basis_link)
576 result.append(this)
577 basis_orig = color_amp.ColorBasis()
578 for ind, new_dict in enumerate(col_obj):
579 basis_orig.update_color_basis(new_dict, ind)
580
581 for link in result:
582 link['orig_basis'] = basis_orig
583 return result
584
588 """Finds all the possible color(charge) links between any
589 two legs of the born.
590 If symm is true, only half of the color links are generated, those
591 for which leg1['number'] <= leg2['number']
592 """
593 if pert == 'QCD':
594 color = 'color'
595 zero = 1
596 elif pert == 'QED':
597 color = 'charge'
598 zero = 0.
599 else:
600 raise FKSProcessError,"Only QCD or QED is allowed not %s" % pert
601 color_links = []
602 for leg1 in leglist:
603 for leg2 in leglist:
604
605 if (leg1.get(color) != zero and leg2.get(color) != zero) \
606 and (leg1 != leg2 or not leg1.get('massless')):
607 if not symm or leg1['number'] <= leg2['number']:
608 col_dict = legs_to_color_link_string(leg1,leg2,pert = pert)
609 color_links.append({
610 'legs': [leg1, leg2],
611 'string': col_dict['string'],
612 'replacements': col_dict['replacements']})
613
614 return color_links
615
618 """given two FKSlegs, returns a dictionary containing:
619 --string: the color link between the two particles, to be appended to
620 the old color string
621 extra minus or 1/2 factor are included as it was done in MadDipole
622 --replacements: a pair of lists containing the replacements of the color
623 indices in the old string to match the link
624 """
625
626
627
628 legs = FKSLegList([leg1, leg2])
629 dict = {}
630 min_index = -3000
631 iglu = min_index*2
632 string = color_algebra.ColorString()
633 replacements = []
634 if pert == 'QCD':
635 if leg1 != leg2:
636 for leg in legs:
637 min_index -= 1
638 num = leg.get('number')
639 replacements.append([num, min_index])
640 icol = 1
641 if not leg.get('state'):
642 icol = - 1
643 if leg.get('color') * icol == 3:
644 string.product(color_algebra.ColorString([
645 color_algebra.T(iglu, num, min_index)]))
646 string.coeff = string.coeff * (-1)
647 elif leg.get('color') * icol == - 3:
648 string.product(color_algebra.ColorString([
649 color_algebra.T(iglu, min_index, num)]))
650 elif leg.get('color') == 8:
651 string.product(color_algebra.ColorString(init_list = [
652 color_algebra.f(min_index,iglu,num)],
653 is_imaginary =True))
654
655 else:
656 icol = 1
657 if not leg1.get('state'):
658 icol = - 1
659 num = leg1.get('number')
660 replacements.append([num, min_index -1])
661 if leg1.get('color') * icol == 3:
662 string = color_algebra.ColorString(
663 [color_algebra.T(iglu, iglu, num, min_index -1)])
664 elif leg1.get('color') * icol == - 3:
665 string = color_algebra.ColorString(
666 [color_algebra.T(iglu, iglu, min_index-1, num)])
667 elif leg1.get('color') == 8:
668 string = color_algebra.ColorString(init_list = [
669 color_algebra.f(min_index-1,iglu,min_index)],
670 is_imaginary =True)
671 string.product(color_algebra.ColorString(init_list = [
672 color_algebra.f(min_index,iglu,num)],
673 is_imaginary =True))
674 string.coeff = string.coeff * fractions.Fraction(1, 2)
675
676 elif pert == 'QED':
677 for leg in legs:
678
679 string.coeff = string.coeff * fractions.Fraction(leg['charge']*3.)*\
680 fractions.Fraction(1,3)
681 else:
682 raise FKSProcessError,"Only QCD or QED is allowed not %s"% pert
683
684 dict['replacements'] = replacements
685 dict['string'] = string
686 return dict
687
690 """Given a process, this function returns the same process
691 but with sorted FKSLegs.
692 """
693 leglist = to_fks_legs(process.get('legs'), process.get('model'))
694 leglist.sort(pert = pert)
695 for n, leg in enumerate(leglist):
696 leg['number'] = n + 1
697 process['legs'] = leglist
698
699 process['legs_with_decays']=MG.LegList()
700
701 return process
702
705 """Given a FKSLeg, returns the original Leg.
706 """
707 leg = MG.Leg( \
708 {'id': fksleg.get('id'),
709 'number': fksleg.get('number'),
710 'state': fksleg.get('state'),
711 'from_group': fksleg.get('from_group'),
712 })
713 return leg
714
717 """Given a FKSLegList, returns the corresponding LegList.
718 """
719 leglist = MG.LegList()
720 for leg in fkslegs:
721 leglist.append(to_leg(leg))
722 return leglist
723
726 """Given a leg or a dict with Leg entries,
727 adds color, spin and massless entries, according to model"""
728 fksleg = FKSLeg(leg)
729 part = model.get('particle_dict')[leg['id']]
730 fksleg['color'] = part.get_color()
731 fksleg['charge'] = part.get_charge()
732 fksleg['massless'] = part['mass'].lower() == 'zero'
733 fksleg['spin'] = part.get('spin')
734 fksleg['is_part'] = part.get('is_part')
735 fksleg['self_antipart'] = part.get('self_antipart')
736 return fksleg
737
740 """given leglist, sets color and massless entries according to the model
741 variable.
742 return a FKSLeglist"""
743 fkslegs = FKSLegList()
744 for leg in leglist:
745 fkslegs.append(to_fks_leg(leg, model))
746 return fkslegs
747
750 """list of FKSLegs"""
751
753 """Test if object obj is a valid FKSLeg for the list."""
754 return isinstance(obj, FKSLeg)
755
756
757 - def sort(self,pert='QCD'):
758 """Sorting routine, sorting chosen to be optimal for madfks"""
759 sorted_leglist = FKSLegList()
760
761 initial_legs = FKSLegList([l for l in copy.copy(self) if not l['state']])
762
763 final_legs = FKSLegList([l for l in copy.copy(self) if l['state']])
764 if len(initial_legs) == 1:
765 sorted_leglist.extend(initial_legs)
766 elif len(initial_legs) == 2:
767 if initial_legs[0]['number'] > initial_legs[1]['number']:
768 initial_legs.reverse()
769 sorted_leglist.extend(initial_legs)
770 else:
771 raise FKSProcessError('Too many initial legs')
772
773
774
775 massive_legs = [l for l in final_legs if not l['massless']]
776 massless_legs = [l for l in final_legs if l['massless']]
777
778 for leglist in [massive_legs, massless_legs]:
779 spins = sorted(set([abs(l['spin']) for l in leglist]))
780 for spin in spins:
781 spin_legs = FKSLegList([l for l in leglist if abs(l['spin']) == spin])
782
783 init_pdg_legs = []
784 if len(initial_legs) == 2:
785
786 for j in range(len(set([ abs(l['id']) for l in initial_legs]))):
787 pdg = abs(initial_legs[j]['id'])
788 init_pdg_legs = [l for l in spin_legs if abs(l['id']) == pdg]
789 if init_pdg_legs:
790
791
792 init_pdg_legs.sort(key = itemgetter('id'), reverse=True)
793 sorted_leglist.extend(FKSLegList(init_pdg_legs))
794
795 init_pdgs = [ abs(l['id']) for l in initial_legs]
796 other_legs = [l for l in spin_legs if not abs(l['id']) in init_pdgs]
797 other_legs.sort(key = itemgetter('id'), reverse=True)
798 sorted_leglist.extend(FKSLegList(other_legs))
799 else:
800
801 sorted_leglist.extend(FKSLegList(spin_legs))
802
803 for i, l in enumerate(sorted_leglist):
804 self[i] = l
805
808 """a class for FKS legs: it inherits from the ususal leg class, with two
809 extra keys in the dictionary:
810 -'fks', whose value can be 'i', 'j' or 'n' (for "normal" particles)
811 -'color', which gives the color of the leg
812 -'charge', which gives the charge of the leg
813 -'massless', boolean, true if leg is massless
814 -'spin' which gives the spin of leg
815 -'is_part', boolean, true if leg is an particle
816 -'self_antipart', boolean, true if leg is an self-conjugated particle
817 """
818
820 """Default values for all properties"""
821 super(FKSLeg, self).default_setup()
822
823 self['fks'] = 'n'
824 self['color'] = 0
825 self['charge'] = 0.
826 self['massless'] = True
827 self['spin'] = 0
828 self['is_part'] = True
829 self['self_antipart'] = False
830
832 """Return particle property names as a nicely sorted list."""
833 keys = super(FKSLeg, self).get_sorted_keys()
834 keys += ['fks', 'color','charge', 'massless', 'spin','is_part','self_antipart']
835 return keys
836
837
838 - def filter(self, name, value):
839 """Filter for valid leg property values."""
840
841 if name == 'fks':
842 if not isinstance(value, str):
843 raise self.PhysicsObjectError, \
844 "%s is not a valid string for leg fks flag" \
845 % str(value)
846 if name in ['color', 'spin']:
847 if not isinstance(value, int):
848 raise self.PhysicsObjectError, \
849 "%s is not a valid leg %s flag" % \
850 str(value),name
851
852 if name in ['massless','self_antipart','is_part']:
853 if not isinstance(value, bool):
854 raise self.PhysicsObjectError, \
855 "%s is not a valid boolean for leg flag %s" % \
856 str(value),name
857 if name is 'charge':
858 if not isinstance(value, float):
859 raise self.PhysicsObjectError, \
860 "%s is not a valid float for leg flag charge" \
861 % str(value)
862 return super(FKSLeg,self).filter(name, value)
863