def test_Tr_product(self): """Test a non trivial product of two traces""" my_color_factor = color.ColorFactor([\ color.ColorString([color.Tr(1, 2, 3, 4, 5, 6, 7), color.Tr(1, 7, 6, 5, 4, 3, 2)])]) self.assertEqual(str(my_color_factor.full_simplify()), "(1/128 Nc^7 )+(-7/128 Nc^5 )+(21/128 Nc^3 )+(-35/128 Nc^1 )" + \ "+(35/128 1/Nc^1 )+(-21/128 1/Nc^3 )+(3/64 1/Nc^5 )")
def test_d_object(self): """Test the d color object""" # T should have exactly 3 indices! self.assertRaises(AssertionError, color.d, 1, 2) # Simplify should always return the same ColorFactor my_d = color.d(1, 2, 3) col_str1 = color.ColorString([color.Tr(1, 2, 3)]) col_str2 = color.ColorString([color.Tr(3, 2, 1)]) col_str1.coeff = fractions.Fraction(2, 1) col_str2.coeff = fractions.Fraction(2, 1) self.assertEqual(my_d.simplify(), color.ColorFactor([col_str1, col_str2]))
def test_f_object(self): """Test the f color object""" # T should have exactly 3 indices! self.assertRaises(AssertionError, color.f, 1, 2, 3, 4) # Simplify should always return the same ColorFactor my_f = color.f(1, 2, 3) col_str1 = color.ColorString([color.Tr(1, 2, 3)]) col_str2 = color.ColorString([color.Tr(3, 2, 1)]) col_str1.coeff = fractions.Fraction(-2, 1) col_str2.coeff = fractions.Fraction(2, 1) col_str1.is_imaginary = True col_str2.is_imaginary = True self.assertEqual(my_f.simplify(), color.ColorFactor([col_str1, col_str2]))
def closeColorLoop(self, colorize_dict, lcut_charge, lcut_numbers): """ Add a color delta in the right representation (depending on the color charge carried by the L-cut particle whose number are given in the loop_numbers argument) to close the loop color trace """ # But for T3 and T6 for example, we must make sure to add a delta with # the first index in the fundamental representation. if lcut_charge < 0: lcut_numbers.reverse() if abs(lcut_charge) == 1: # No color carried by the lcut particle, there is nothing to do. return elif abs(lcut_charge) == 3: closingCS=color_algebra.ColorString(\ [color_algebra.T(lcut_numbers[1],lcut_numbers[0])]) elif abs(lcut_charge) == 6: closingCS=color_algebra.ColorString(\ [color_algebra.T6(lcut_numbers[1],lcut_numbers[0])]) elif abs(lcut_charge) == 8: closingCS=color_algebra.ColorString(\ [color_algebra.Tr(lcut_numbers[1],lcut_numbers[0])], fractions.Fraction(2, 1)) else: raise color_amp.ColorBasis.ColorBasisError, \ "L-cut particle has an unsupported color representation %s" % lcut_charge # Append it to all color strings for this diagram. for CS in colorize_dict.values(): CS.product(closingCS)
def test_color_flow_string(self): """Test the color flow decomposition of various color strings""" # qq~>qq~ my_cs = color.ColorString([color.T(-1000, 1, 2), color.T(-1000, 3, 4)]) goal_cs = color.ColorString([color.T(1, 4), color.T(3, 2)]) goal_cs.coeff = fractions.Fraction(1, 2) self.assertEqual(color_amp.ColorBasis.get_color_flow_string(my_cs, []), goal_cs) # qq~>qq~g my_cs = color.ColorString( [color.T(-1000, 1, 2), color.T(-1000, 3, 4), color.T(5, 4, 6)]) goal_cs = color.ColorString( [color.T(1, 2005), color.T(3, 2), color.T(1005, 6)]) goal_cs.coeff = fractions.Fraction(1, 4) self.assertEqual( color_amp.ColorBasis.get_color_flow_string(my_cs, [(8, 5, 1005, 2005)]), goal_cs) # gg>gg my_cs = color.ColorString( [color.Tr(-1000, 1, 2), color.Tr(-1000, 3, 4)]) goal_cs = color.ColorString([ color.T(1001, 2002), color.T(1002, 2003), color.T(1003, 2004), color.T(1004, 2001) ]) goal_cs.coeff = fractions.Fraction(1, 32) self.assertEqual( color_amp.ColorBasis.get_color_flow_string(my_cs, [(8, 1, 1001, 2001), (8, 2, 1002, 2002), (8, 3, 1003, 2003), (8, 4, 1004, 2004)]), goal_cs)
def closeColorLoop(self, colorize_dict, lcut_charge, lcut_numbers): """ Add a color delta in the right representation (depending on the color charge carried by the L-cut particle whose number are given in the loop_numbers argument) to close the loop color trace.""" # But for T3 and T6 for example, we must make sure to add a delta with # the first index in the fundamental representation. if lcut_charge < 0: lcut_numbers.reverse() if abs(lcut_charge) == 1: # No color carried by the lcut particle, there is nothing to do. return elif abs(lcut_charge) == 3: closingCS=color_algebra.ColorString(\ [color_algebra.T(lcut_numbers[1],lcut_numbers[0])]) elif abs(lcut_charge) == 6: closingCS=color_algebra.ColorString(\ [color_algebra.T6(lcut_numbers[1],lcut_numbers[0])]) elif abs(lcut_charge) == 8: closingCS=color_algebra.ColorString(\ [color_algebra.Tr(lcut_numbers[1],lcut_numbers[0])], fractions.Fraction(2, 1)) else: raise color_amp.ColorBasis.ColorBasisError, \ "L-cut particle has an unsupported color representation %s" % lcut_charge # Append it to all color strings for this diagram. for CS in colorize_dict.values(): # The double full_simplify() below brings significantly slowdown # so that it should be used only when loop_Nc_power is actuall used. if self.compute_loop_nc: # We first compute the NcPower of this ColorString before # *before* the loop color flow is sewed together. max_CS_lcut_diag_Nc_power = max(cs.Nc_power \ for cs in color_algebra.ColorFactor([CS]).full_simplify()) # We add here the closing color structure. CS.product(closingCS) if self.compute_loop_nc: # Now compute the Nc power *after* the loop color flow is sewed # together and again compute the overall maximum power of Nc # appearing in this simplified sewed structure. simplified_cs = color_algebra.ColorFactor([CS]).full_simplify() if not simplified_cs: # It can be that the color structure simplifies to zero. CS.loop_Nc_power = 0 continue max_CS_loop_diag_Nc_power = max(cs.Nc_power \ for cs in simplified_cs) # We can now set the power of Nc brought by the potential loop # color trace to the corresponding attribute of this ColorStructure CS.loop_Nc_power = max_CS_loop_diag_Nc_power - \ max_CS_lcut_diag_Nc_power else: # When not computing loop_nc (whcih is typically used for now # only when doing LoopInduced + Madevent, we set the # CS.loop_Nc_power to None so that it will cause problems if used. CS.loop_Nc_power = None
def test_complex_conjugate(self): """Test the complex conjugation of a color string""" my_color_string = color.ColorString([color.T(3, 4, 102, 103), color.Tr(1, 2, 3)]) my_color_string.is_imaginary = True self.assertEqual(str(my_color_string.complex_conjugate()), '-1 I T(4,3,103,102) Tr(3,2,1)')
def test_T_simplify(self): """Test T simplify""" # T(a,b,c,...,i,i) = Tr(a,b,c,...) self.assertEqual(color.T(1, 2, 3, 100, 100).simplify(), color.ColorFactor([\ color.ColorString([color.Tr(1, 2, 3)])])) # T(a,x,b,x,c,i,j) = 1/2(T(a,c,i,j)Tr(b)-1/Nc T(a,b,c,i,j)) my_T = color.T(1, 2, 100, 3, 100, 4, 101, 102) col_str1 = color.ColorString([color.T(1, 2, 4, 101, 102), color.Tr(3)]) col_str2 = color.ColorString([color.T(1, 2, 3, 4, 101, 102)]) col_str1.coeff = fractions.Fraction(1, 2) col_str2.coeff = fractions.Fraction(-1, 2) col_str2.Nc_power = -1 self.assertEqual(my_T.simplify(), color.ColorFactor([col_str1, col_str2])) self.assertEqual(my_T.simplify(), color.ColorFactor([col_str1, col_str2]))
def test_replace_indices(self): """Test indices replacement""" repl_dict = {1: 2, 2: 3, 3: 1} my_color_string = color.ColorString( [color.T(1, 2, 3, 4), color.Tr(3, 2, 1)]) my_color_string.replace_indices(repl_dict) self.assertEqual(str(my_color_string), '1 T(2,3,1,4) Tr(1,3,2)') inv_repl_dict = dict([v, k] for k, v in repl_dict.items()) my_color_string.replace_indices(inv_repl_dict) self.assertEqual(str(my_color_string), '1 T(1,2,3,4) Tr(3,2,1)')
def test_Tr_pair_simplify(self): """Test Tr object product simplification""" my_Tr1 = color.Tr(1, 2, 3) my_Tr2 = color.Tr(4, 2, 5) my_T = color.T(4, 2, 5, 101, 102) col_str1 = color.ColorString([color.Tr(1, 5, 4, 3)]) col_str2 = color.ColorString([color.Tr(1, 3), color.Tr(4, 5)]) col_str1.coeff = fractions.Fraction(1, 2) col_str2.coeff = fractions.Fraction(-1, 2) col_str2.Nc_power = -1 self.assertEqual(my_Tr1.pair_simplify(my_Tr2), color.ColorFactor([col_str1, col_str2])) col_str1 = color.ColorString([color.T(4, 3, 1, 5, 101, 102)]) col_str2 = color.ColorString([color.Tr(1, 3), color.T(4, 5, 101, 102)]) col_str1.coeff = fractions.Fraction(1, 2) col_str2.coeff = fractions.Fraction(-1, 2) col_str2.Nc_power = -1 self.assertEqual(my_Tr1.pair_simplify(my_T), color.ColorFactor([col_str1, col_str2]))
def read_interactions_v4(fsock, ref_part_list): """Read a list of interactions from stream fsock, using the old v4 format. Requires a ParticleList object as an input to recognize particle names.""" logger.info('load interactions') myinterlist = InteractionList() if not isinstance(ref_part_list, ParticleList): raise ValueError, \ "Object %s is not a valid ParticleList" % repr(ref_part_list) for line in fsock: myinter = Interaction() line = line.split("#", 2)[0] # remove any comment line = line.strip() # makes the string clean if line != "": # skip blank values = line.split() part_list = ParticleList() try: for str_name in values: curr_part = ref_part_list.get_copy(str_name.lower()) if isinstance(curr_part, Particle): # Look at the total number of strings, stop if # anyway not enough, required if a variable name # corresponds to a particle! (eg G) if len(values) >= 2 * len(part_list) + 1: part_list.append(curr_part) else: break # also stops if string does not correspond to # a particle name else: break if len(part_list) < 3: raise Interaction.PhysicsObjectError, \ "Vertex with less than 3 known particles found." # Flip part/antipart of first part for FFV, FFS, FFT vertices # according to v4 convention spin_array = [part['spin'] for part in part_list] if spin_array[:2] == [2, 2] and \ not part_list[0].get('self_antipart'): part_list[0]['is_part'] = not part_list[0]['is_part'] myinter.set('particles', part_list) # Give color structure # Order particles according to color # Don't consider singlets color_parts = sorted(enumerate(part_list), lambda p1, p2:\ p1[1].get_color() - p2[1].get_color()) color_ind = [(i, part.get_color()) for i, part in \ color_parts if part.get_color() !=1] colors = [c for i, c in color_ind] ind = [i for i, c in color_ind] # Set color empty by default myinter.set('color', []) if not colors: # All color singlets - set empty pass elif colors == [-3, 3]: # triplet-triplet-singlet coupling myinter.set('color', [color.ColorString(\ [color.T(ind[1], ind[0])])]) elif colors == [8, 8]: # octet-octet-singlet coupling my_cs = color.ColorString(\ [color.Tr(ind[0], ind[1])]) my_cs.coeff = fractions.Fraction(2) myinter.set('color', [my_cs]) elif colors == [-3, 3, 8]: # triplet-triplet-octet coupling myinter.set('color', [color.ColorString(\ [color.T(ind[2], ind[1], ind[0])])]) elif colors == [8, 8, 8]: # Triple glue coupling my_color_string = color.ColorString(\ [color.f(ind[0], ind[1], ind[2])]) my_color_string.is_imaginary = True myinter.set('color', [my_color_string]) elif colors == [-3, 3, 8, 8]: my_cs1 = color.ColorString(\ [color.T(ind[2], ind[3], ind[1], ind[0])]) my_cs2 = color.ColorString(\ [color.T(ind[3], ind[2], ind[1], ind[0])]) myinter.set('color', [my_cs1, my_cs2]) elif colors == [8, 8, 8, 8]: # 4-glue coupling cs1 = color.ColorString( [color.f(0, 1, -1), color.f(2, 3, -1)]) #cs1.coeff = fractions.Fraction(-1) cs2 = color.ColorString( [color.f(2, 0, -1), color.f(1, 3, -1)]) #cs2.coeff = fractions.Fraction(-1) cs3 = color.ColorString( [color.f(1, 2, -1), color.f(0, 3, -1)]) #cs3.coeff = fractions.Fraction(-1) myinter.set('color', [cs1, cs2, cs3]) # The following line are expected to be correct but not physical validations # have been performed. So we keep it commented for the moment. # elif colors == [3, 3, 3]: # my_color_string = color.ColorString(\ # [color.Epsilon(ind[0], ind[1], ind[2])]) # myinter.set('color', [my_color_string]) # elif colors == [-3, -3, -3]: # my_color_string = color.ColorString(\ # [color.EpsilonBar(ind[0], ind[1], ind[2])]) # myinter.set('color', [my_color_string]) else: logger.warning(\ "Color combination %s not yet implemented." % \ repr(colors)) # Set the Lorentz structure. Default for 3-particle # vertices is empty string, for 4-particle pair of # empty strings myinter.set('lorentz', ['']) pdg_codes = sorted([part.get_pdg_code() for part in part_list]) # WWWW and WWVV if pdg_codes == [-24, -24, 24, 24]: myinter.set('lorentz', ['WWWW']) elif spin_array == [3, 3, 3, 3] and \ 24 in pdg_codes and - 24 in pdg_codes: myinter.set('lorentz', ['WWVV']) # gggg if pdg_codes == [21, 21, 21, 21]: myinter.set('lorentz', ['gggg1', 'gggg2', 'gggg3']) # go-go-g # Using the special fvigox routine provides the minus # sign necessary for octet Majorana-vector interactions if spin_array == [2, 2, 3] and colors == [8, 8, 8] and \ part_list[0].get('self_antipart') and \ part_list[1].get('self_antipart'): myinter.set('lorentz', ['go']) # If extra flag, add this to Lorentz if len(values) > 3 * len(part_list) - 4: myinter.get('lorentz')[0] = \ myinter.get('lorentz')[0]\ + values[3 * len(part_list) - 4].upper() # Use the other strings to fill variable names and tags # Couplings: special treatment for 4-vertices, where MG4 used # two couplings, while MG5 only uses one (with the exception # of the 4g vertex, which needs special treatment) # DUM0 and DUM1 are used as placeholders by FR, corresponds to 1 if len(part_list) == 3 or \ values[len(part_list) + 1] in ['DUM', 'DUM0', 'DUM1']: # We can just use the first coupling, since the second # is a dummy myinter.set('couplings', {(0, 0): values[len(part_list)]}) if myinter.get('lorentz')[0] == 'WWWWN': # Should only use one Helas amplitude for electroweak # 4-vector vertices with FR. I choose W3W3NX. myinter.set('lorentz', ['WWVVN']) elif values[len(part_list)] in ['DUM', 'DUM0', 'DUM1']: # We can just use the second coupling, since the first # is a dummy myinter.set('couplings', {(0, 0): values[len(part_list) + 1]}) elif pdg_codes == [21, 21, 21, 21]: # gggg myinter.set( 'couplings', { (0, 0): values[len(part_list)], (1, 1): values[len(part_list)], (2, 2): values[len(part_list)] }) elif myinter.get('lorentz')[0] == 'WWWW': # Need special treatment of v4 SM WWWW couplings since # MG5 can only have one coupling per Lorentz structure myinter.set('couplings', {(0, 0):\ 'sqrt(' + values[len(part_list)] + \ '**2+' + \ values[len(part_list) + 1] + \ '**2)'}) else: #if myinter.get('lorentz')[0] == 'WWVV': # Need special treatment of v4 SM WWVV couplings since # MG5 can only have one coupling per Lorentz structure myinter.set('couplings', {(0, 0):values[len(part_list)] + \ '*' + \ values[len(part_list) + 1]}) #raise Interaction.PhysicsObjectError, \ # "Only FR-style 4-vertices implemented." # SPECIAL TREATMENT OF COLOR # g g sq sq (two different color structures, same Lorentz) if spin_array == [3, 3, 1, 1] and colors == [-3, 3, 8, 8]: myinter.set( 'couplings', { (0, 0): values[len(part_list)], (1, 0): values[len(part_list)] }) # Coupling orders - needs to be fixed order_list = values[2 * len(part_list) - 2: \ 3 * len(part_list) - 4] def count_duplicates_in_list(dupedlist): """return a dictionary with key the element of dupeList and with value the number of times that they are in this list""" unique_set = set(item for item in dupedlist) ret_dict = {} for item in unique_set: ret_dict[item] = dupedlist.count(item) return ret_dict myinter.set('orders', count_duplicates_in_list(order_list)) myinter.set('id', len(myinterlist) + 1) myinterlist.append(myinter) except Interaction.PhysicsObjectError, why: logger.error("Interaction ignored: %s" % why)
def test_sextet_products(self): """Test non trivial product of sextet operators""" # T6[2, 101, 102] T6[2, 102, 103] = (-1 + Nc) (2 + Nc) delta6[101, 103])/Nc my_color_factor = color.ColorFactor([\ color.ColorString([color.T6(2, 101, 102), color.T6(2, 102, 103)])]) col_str1 = color.ColorString([color.T6(101,103)]) col_str1.Nc_power = 1 col_str2 = copy.copy(col_str1) col_str2.Nc_power = 0 col_str3 = copy.copy(col_str1) col_str3.Nc_power = -1 col_str3.coeff = fractions.Fraction(-2, 1) self.assertEqual(my_color_factor.full_simplify(), color.ColorFactor([col_str1, col_str2, col_str3])) # T6[2, 101, 102] T6[3, 102, 101] = 1/2 (2 + Nc) delta8[2, 3] my_color_factor = color.ColorFactor([\ color.ColorString([color.T6(2, 101, 102), color.T6(3, 102, 101)])]) col_str1 = color.ColorString([color.Tr(2,3)]) col_str1.Nc_power = 1 col_str1.coeff = fractions.Fraction(1) col_str2 = copy.copy(col_str1) col_str2.Nc_power = 0 col_str2.coeff = fractions.Fraction(2) self.assertEqual(my_color_factor.full_simplify(), color.ColorFactor([col_str1, col_str2])) # K6[1, 101, 102] T[2, 102, 103] T[2, 103, 104] K6Bar[1, 104, 101] # = 1/4 (-1 + Nc) (1 + Nc)^2 # = 1/4 (-1 - Nc + Nc^2 + Nc^3) my_color_factor = color.ColorFactor([\ color.ColorString([color.K6(1, 101, 102), color.T(2, 102, 103), color.T(2, 103, 104), color.K6Bar(1, 104, 101)])]) col_str1 = color.ColorString() col_str1.Nc_power = 3 col_str1.coeff = fractions.Fraction(1, 4) col_str2 = color.ColorString() col_str2.Nc_power = 2 col_str2.coeff = fractions.Fraction(1, 4) col_str3 = color.ColorString() col_str3.Nc_power = 1 col_str3.coeff = fractions.Fraction(-1, 4) col_str4 = color.ColorString() col_str4.Nc_power = 0 col_str4.coeff = fractions.Fraction(-1, 4) self.assertEqual(my_color_factor.full_simplify(), color.ColorFactor([col_str1, col_str3, col_str2, col_str4])) # T6[2, 101, 102] T6[2, 102, 103] K6[103, 99, 98] K6Bar[101, 98, 99] # = 1/2 (-1 + Nc) (1 + Nc) (2 + Nc) # = 1/2 (Nc^3 + 2 Nc^2 - Nc - 2) my_color_factor = color.ColorFactor([\ color.ColorString([color.T6(2, 101, 102), color.T6(2, 102, 103), color.K6(103,99, 98), color.K6Bar(101, 98, 99)])]) col_str1 = color.ColorString() col_str1.Nc_power = 3 col_str1.coeff = fractions.Fraction(1, 2) col_str2 = color.ColorString() col_str2.Nc_power = 2 col_str2.coeff = fractions.Fraction(1, 1) col_str3 = color.ColorString() col_str3.Nc_power = 1 col_str3.coeff = fractions.Fraction(-1, 2) col_str4 = color.ColorString() col_str4.Nc_power = 0 col_str4.coeff = fractions.Fraction(-1, 1) self.assertEqual(my_color_factor.full_simplify(), color.ColorFactor([col_str2, col_str1, col_str3, col_str4])) # K6[103, 99, 98] T[80, 98, 100] K6Bar[103, 100, 97] T[80, 99, 97] # = -(1/4) + Nc^2/4 my_color_factor = color.ColorFactor([\ color.ColorString([color.K6(103, 99, 98), color.T(80, 98, 100), color.K6Bar(103, 100, 97), color.T(80, 99, 97)])]) col_str1 = color.ColorString() col_str1.Nc_power = 2 col_str1.coeff = fractions.Fraction(1, 4) col_str2 = color.ColorString() col_str2.Nc_power = 0 col_str2.coeff = fractions.Fraction(-1, 4) self.assertEqual(my_color_factor.full_simplify(), color.ColorFactor([col_str1, col_str2]))
def test_Tr_simplify(self): """Test simplification of trace objects""" # Test Tr(a)=0 self.assertEqual(color.Tr(-1).simplify(), color.ColorFactor([color.ColorString(coeff=0)])) # Test Tr()=Nc col_str = color.ColorString() col_str.Nc_power = 1 self.assertEqual(color.Tr().simplify(), color.ColorFactor([col_str])) # Test cyclicity col_str = color.ColorString([color.Tr(1, 2, 3, 4, 5)]) self.assertEqual(color.Tr(3, 4, 5, 1, 2).simplify(), color.ColorFactor([col_str])) # Tr(a,x,b,x,c) = 1/2(Tr(a,c)Tr(b)-1/Nc Tr(a,b,c)) col_str1 = color.ColorString([color.Tr(1, 2, 4), color.Tr(3)]) col_str2 = color.ColorString([color.Tr(1, 2, 3, 4)]) col_str1.coeff = fractions.Fraction(1, 2) col_str2.coeff = fractions.Fraction(-1, 2) col_str2.Nc_power = -1 my_tr = color.Tr(1, 2, 100, 3, 100, 4) self.assertEqual(my_tr.simplify(), color.ColorFactor([col_str1, col_str2])) my_tr = color.Tr(1, 2, 100, 100, 4) col_str1 = color.ColorString([color.Tr(1, 2, 4), color.Tr()]) col_str2 = color.ColorString([color.Tr(1, 2, 4)]) col_str1.coeff = fractions.Fraction(1, 2) col_str2.coeff = fractions.Fraction(-1, 2) col_str2.Nc_power = -1 self.assertEqual(my_tr.simplify(), color.ColorFactor([col_str1, col_str2])) my_tr = color.Tr(100, 100) col_str1 = color.ColorString([color.Tr(), color.Tr()]) col_str2 = color.ColorString([color.Tr()]) col_str1.coeff = fractions.Fraction(1, 2) col_str2.coeff = fractions.Fraction(-1, 2) col_str2.Nc_power = -1 self.assertEqual(my_tr.simplify(), color.ColorFactor([col_str1, col_str2]))