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