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