def test_find_symmetry_decay_chain_with_subprocess_group(self): """Test the find_symmetry function for subprocess groups""" procs = [[2, -1, 24, 21, 21], [-3, 4, 24, 21, 21]] decays = [[24, -11, 12], [24, -13, 14]] amplitudes = diagram_generation.AmplitudeList() decay_amps = diagram_generation.DecayChainAmplitudeList() for proc, decay in zip(procs, decays): # Define the multiprocess my_leglist = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in proc]) my_leglist[0].set('state', False) my_leglist[1].set('state', False) my_decaylegs = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in decay]) my_decaylegs[0].set('state', False) my_process = base_objects.Process({ 'legs': my_leglist, 'model': self.base_model }) my_decay_proc = base_objects.Process({ 'legs': my_decaylegs, 'model': self.base_model, 'is_decay_chain': True }) my_amplitude = diagram_generation.Amplitude(my_process) my_decay = diagram_generation.DecayChainAmplitude(my_decay_proc) amplitudes.append(my_amplitude) decay_amps.append(my_decay) amplitudes = diagram_generation.DecayChainAmplitudeList([\ diagram_generation.DecayChainAmplitude({\ 'amplitudes': amplitudes, 'decay_chains': decay_amps})]) subproc_groups = \ group_subprocs.DecayChainSubProcessGroup.group_amplitudes(\ amplitudes,"madevent").generate_helas_decay_chain_subproc_groups() self.assertEqual(len(subproc_groups), 1) subproc_group = subproc_groups[0] self.assertEqual(len(subproc_group.get('matrix_elements')), 2) symmetry, perms, ident_perms = diagram_symmetry.find_symmetry(\ subproc_group) self.assertEqual(len([s for s in symmetry if s > 0]), 5) self.assertEqual(symmetry, [1, -1, 1, 1, 1, -4, -5, 1])
def test_find_symmetry_gg_tt_fullylept(self): """Test the find_symmetry function for subprocess groups""" procs = [[21,21, 6, -6]] decayt = [[6,5,-11,12],[6, 5,-13, 14]] decaytx = [[-6,-5,11,-12],[-6, -5, 13,-14]] amplitudes = diagram_generation.AmplitudeList() decay_amps = diagram_generation.DecayChainAmplitudeList() proc = procs[0] my_leglist = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in proc]) my_leglist[0].set('state', False) my_leglist[1].set('state', False) my_process = base_objects.Process({'legs':my_leglist, 'model':self.base_model}) my_amplitude = diagram_generation.Amplitude(my_process) amplitudes.append(my_amplitude) for dect in decayt: my_top_decaylegs = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in dect]) my_top_decaylegs[0].set('state', False) my_decayt_proc = base_objects.Process({'legs':my_top_decaylegs, 'model':self.base_model, 'is_decay_chain': True}) my_decayt = diagram_generation.DecayChainAmplitude(my_decayt_proc) decay_amps.append(my_decayt) for dectx in decaytx: # Define the multiprocess my_topx_decaylegs = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in dectx]) my_topx_decaylegs[0].set('state', False) my_decaytx_proc = base_objects.Process({'legs':my_topx_decaylegs, 'model':self.base_model, 'is_decay_chain': True}) my_decaytx = diagram_generation.DecayChainAmplitude(my_decaytx_proc) decay_amps.append(my_decaytx) amplitudes = diagram_generation.DecayChainAmplitudeList([\ diagram_generation.DecayChainAmplitude({\ 'amplitudes': amplitudes, 'decay_chains': decay_amps})]) subproc_groups = \ group_subprocs.DecayChainSubProcessGroup.group_amplitudes(\ amplitudes).generate_helas_decay_chain_subproc_groups() self.assertEqual(len(subproc_groups), 1) subproc_group = subproc_groups[0] self.assertEqual(len(subproc_group.get('matrix_elements')), 1) symmetry, perms, ident_perms = diagram_symmetry.find_symmetry(\ subproc_group) sol_perms = [list(range(8)), list(range(8)), [0,1,5,6,7,2,3,4]] self.assertEqual(len([s for s in symmetry if s > 0]), 2) self.assertEqual(symmetry, [1, 1, -2]) self.assertEqual(perms, sol_perms)
def find_os_divergences(fksreal): """this function looks for possible on shell contributions to be removed. In order to be agnostic on mass hierarchies all splittings 1->2 3 are investigated, with m1 != 0, m2, m3 != m1 since these resonances are introduced at the real-emission level, one must have m2=0 or m3=0 """ if type(fksreal) == fks_base.FKSRealProcess: process = fksreal.process amplitude = fksreal.amplitude from_helas = False elif type(fksreal) == fks_helas.FKSHelasRealProcess: process = fksreal.matrix_element['processes'][0] amplitude = fksreal.matrix_element['base_amplitude'] from_helas = True else: raise MadSTRFKSError( "Unknown type of fksreal in find_os_divergences: " + type(fksreal)) model = process['model'] forbidden = process['forbidden_particles'] # take account of the orders for the on shell processes weighted_order = process['orders']['WEIGHTED'] fksreal.os_amplitudes = [] fksreal.os_ids = [] fksreal.os_daughter_pos = [] fksreal.os_diagrams = [] # this is a counter to be returned n_os = 0 # focus only on final state legs final_legs = [copy.copy(l) for l in process['legs'] if l['state']] for leg_2 in final_legs: for leg_3 in [l for l in final_legs if l['number'] > leg_2['number']]: # one of the two legs must be massless if not leg_2['massless'] and not leg_3['massless']: continue # prepare the leglist for the 'on shell' process, which should # not contain leg_2 and leg_3, but should contain their mother particle # if it exists other_legs = [copy.copy(l) for l in process['legs'] if \ l != leg_2 and l != leg_3] assert (len(other_legs) == (len(process['legs']) - 2)) leg_2_part = model.get('particle_dict')[leg_2['id']] leg_3_part = model.get('particle_dict')[leg_3['id']] interactions = [inte for inte in model.get('interaction_dict').values() \ if len(inte['particles']) == 3 and \ leg_2_part in inte['particles'] and \ leg_3_part in inte['particles']] for inte in interactions: particles = [copy.copy(p) for p in inte['particles']] try: particles.remove(leg_2_part) particles.remove(leg_3_part) except ValueError: # this is when leg_2 and leg_3 are the same particle # and it appears only once in the interacion, so # the interaction has to be skipped continue leg_1_part = particles[0] # check that it is massive and its mass it is different from # leg_2 and leg_3 if leg_1_part['mass'].lower() == 'zero' or \ leg_1_part['mass'] == leg_2_part['mass'] or \ leg_1_part['mass'] == leg_3_part['mass']: continue # check that it is not among the forbidden particles if leg_1_part.get_pdg_code() in forbidden or \ leg_1_part.get_anti_pdg_code() in forbidden: continue # this should be the final particle (take the antiparticle as # it has to go "into" the interaction) leg_1 = MG.Leg({ 'state': True, 'id': leg_1_part.get_anti_pdg_code(), 'number': leg_2['number'] }) os_legs = [copy.copy(l) for l in other_legs] os_legs.insert(leg_2['number'] - 1, leg_1) assert (len(os_legs) == (len(process['legs']) - 1)) # count the occurences of leg 1 in the final state legs # only one of them has to be decayed nleg_1 = [l['id'] for l in os_legs].count(leg_1['id']) # construct the decay chain and the process # definition leg_1_decay = MG.Leg({'id': leg_1['id'], 'state': False}) leg_2_decay = MG.Leg({'id': leg_2['id'], 'state': True}) leg_3_decay = MG.Leg({'id': leg_3['id'], 'state': True}) decay_chain_legs = MG.LegList(\ [leg_1_decay, leg_2_decay, leg_3_decay]) decay_chain = MG.Process(\ {'model': model, 'legs': MG.LegList(decay_chain_legs), 'is_decay_chain': True}) # construct the 'trivial' decay chain to be used when leg_1 # occurs more than once in the final state legs leg_1_decayed = MG.Leg({'id': leg_1['id'], 'state': True}) trivial_decay_chain_legs = MG.LegList(\ [leg_1_decay, leg_1_decayed]) trivial_decay_chain = MG.Process(\ {'model': model, 'legs': MG.LegList(trivial_decay_chain_legs), 'is_decay_chain': True}) decay_chains = MG.ProcessList([decay_chain] + \ [trivial_decay_chain] * (nleg_1 - 1)) for leg in os_legs: leg['number'] = os_legs.index(leg) + 1 # the orders in os_procdef refer only to the production process # so the orders of the splitting have to be subtracted prod_weighted_order = weighted_order - \ sum([v * model.get('order_hierarchy')[o] \ for o, v in inte['orders'].items()]) # skip if prod_weighted_order is negative or zero # negative prod_weighted_order can lead to strange behaviours if prod_weighted_order < 0: continue os_procdef = MG.Process(\ {'model': model, 'legs': MG.LegList(os_legs), 'decay_chains': decay_chains, 'orders': {'WEIGHTED': prod_weighted_order}}) # now generate the amplitude. # Do nothing if any InvalidCmd is raised (e.g. charge not conserved) # or if no diagrams are there # set the logger to CRITICAL in order not to warn about 1 -> 1 # (trivial) decay chains loglevel = logging.getLogger( 'madgraph.diagram_generation').level logging.getLogger('madgraph.diagram_generation').setLevel( logging.CRITICAL) try: os_amp = diagram_generation.DecayChainAmplitude(os_procdef) except InvalidCmd: continue logging.getLogger('madgraph.diagram_generation').setLevel( loglevel) if not all([amp['diagrams'] for amp in os_amp['amplitudes']]): continue logger.info( 'Process %s has been generated for on-shell subtraction' % os_procdef.input_string()) n_os += 1 fksreal.os_amplitudes.append(os_amp) fksreal.os_ids.append([leg_1['id'], leg_2['id'], leg_3['id']]) fksreal.os_daughter_pos.append( [leg_2['number'] - 1, leg_3['number'] - 1]) fksreal.os_diagrams.append(find_os_diagrams(\ amplitude, [leg_1, leg_2, leg_3], from_helas)) return n_os
def test_ungrouping_lepton(self): """check that the routines which ungroup the process for the muon/electron processes works as expected""" # Setup A simple model mypartlist = base_objects.ParticleList() myinterlist = base_objects.InteractionList() # A quark U and its antiparticle mypartlist.append( base_objects.Particle({ 'name': 'u', 'antiname': 'u~', 'spin': 2, 'color': 3, 'mass': 'zero', 'width': 'zero', 'texname': 'u', 'antitexname': '\bar u', 'line': 'straight', 'charge': 2. / 3., 'pdg_code': 2, 'propagating': True, 'is_part': True, 'self_antipart': False })) u = mypartlist[-1] antiu = copy.copy(u) antiu.set('is_part', False) # A quark D and its antiparticle mypartlist.append( base_objects.Particle({ 'name': 'd', 'antiname': 'd~', 'spin': 2, 'color': 3, 'mass': 'zero', 'width': 'zero', 'texname': 'd', 'antitexname': '\bar d', 'line': 'straight', 'charge': -1. / 3., 'pdg_code': 1, 'propagating': True, 'is_part': True, 'self_antipart': False })) d = mypartlist[-1] antid = copy.copy(d) antid.set('is_part', False) # A quark C and its antiparticle mypartlist.append( base_objects.Particle({ 'name': 'c', 'antiname': 'c~', 'spin': 2, 'color': 3, 'mass': 'zero', 'width': 'zero', 'texname': 'u', 'antitexname': '\bar u', 'line': 'straight', 'charge': 2. / 3., 'pdg_code': 4, 'propagating': True, 'is_part': True, 'self_antipart': False })) c = mypartlist[-1] antic = copy.copy(c) antic.set('is_part', False) # electron/positront mypartlist.append( base_objects.Particle({ 'name': 'e-', 'antiname': 'e+', 'spin': 2, 'color': 1, 'mass': 'zero', 'width': 'zero', 'texname': 'u', 'antitexname': '\bar u', 'line': 'straight', 'charge': 1, 'pdg_code': 11, 'propagating': True, 'is_part': True, 'self_antipart': False })) e = mypartlist[-1] antie = copy.copy(e) mu = copy.copy(e) antie.set('is_part', False) mu.set('name', 'mu-') mu.set('antiname', 'mu+') mu.set('pdg_code', 13) mypartlist.append(mu) antimu = copy.copy(mu) antimu.set('is_part', False) # A Z mypartlist.append( base_objects.Particle({ 'name': 'z', 'antiname': 'z', 'spin': 3, 'color': 1, 'mass': 'MZ', 'width': 'WZ', 'texname': 'Z', 'antitexname': 'Z', 'line': 'wavy', 'charge': 0., 'pdg_code': 23, 'propagating': True, 'is_part': True, 'self_antipart': True })) z = mypartlist[-1] # Coupling of Z to quarks myinterlist.append(base_objects.Interaction({ 'id': 1, 'particles': base_objects.ParticleList(\ [antiu, \ u, \ z]), 'color': [color.ColorString([color.T(1,0)])], 'lorentz':['FFV1', 'FFV2'], 'couplings':{(0, 0):'GUZ1', (0, 1):'GUZ2'}, 'orders':{'QED':1}})) myinterlist.append(base_objects.Interaction({ 'id': 2, 'particles': base_objects.ParticleList(\ [antid, \ d, \ z]), 'color': [color.ColorString([color.T(1,0)])], 'lorentz':['FFV1', 'FFV2'], 'couplings':{(0, 0):'GDZ1', (0, 1):'GDZ2'}, 'orders':{'QED':1}})) myinterlist.append(base_objects.Interaction({ 'id': 3, 'particles': base_objects.ParticleList(\ [antic, \ c, \ z]), 'color': [color.ColorString([color.T(1,0)])], 'lorentz':['FFV1', 'FFV2'], 'couplings':{(0, 0):'GUZ1', (0, 1):'GUZ2'}, 'orders':{'QED':1}})) # Coupling of Z to leptons myinterlist.append(base_objects.Interaction({ 'id': 4, 'particles': base_objects.ParticleList(\ [antie, \ e, \ z]), 'color': [color.ColorString()], 'lorentz':['FFV1', 'FFV2'], 'couplings':{(0, 0):'GLZ1', (0, 1):'GLZ2'}, 'orders':{'QED':1}})) # Coupling of Z to leptons myinterlist.append(base_objects.Interaction({ 'id': 5, 'particles': base_objects.ParticleList(\ [antimu, \ mu, \ z]), 'color': [color.ColorString()], 'lorentz':['FFV1', 'FFV2'], 'couplings':{(0, 0):'GLZ1', (0, 1):'GLZ2'}, 'orders':{'QED':1}})) mymodel = base_objects.Model() mymodel.set('particles', mypartlist) mymodel.set('interactions', myinterlist) mymodel.set('name', 'sm') procs = [[1, -1, 23], [2, -2, 23], [4, -4, 23]] decays = [[23, 11, -11], [23, 13, -13]] coreamplitudes = diagram_generation.AmplitudeList() decayamplitudes = diagram_generation.AmplitudeList() decayprocs = base_objects.ProcessList() #Building the basic objects for proc in procs: # Define the multiprocess my_leglist = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in proc]) my_leglist[0].set('state', False) my_leglist[1].set('state', False) my_process = base_objects.Process({ 'legs': my_leglist, 'model': mymodel }) my_amplitude = diagram_generation.Amplitude(my_process) my_amplitude.set('has_mirror_process', True) coreamplitudes.append(my_amplitude) for proc in decays: # Define the multiprocess my_leglist = base_objects.LegList([\ base_objects.Leg({'id': id, 'state': True}) for id in proc]) my_leglist[0].set('state', False) my_process = base_objects.Process({ 'legs': my_leglist, 'model': mymodel, 'is_decay_chain': True }) my_amplitude = diagram_generation.Amplitude(my_process) decayamplitudes.append(my_amplitude) decayprocs.append(my_process) decays = diagram_generation.DecayChainAmplitudeList([\ diagram_generation.DecayChainAmplitude({\ 'amplitudes': decayamplitudes})]) decay_chains = diagram_generation.DecayChainAmplitude({\ 'amplitudes': coreamplitudes, 'decay_chains': decays}) dc_subproc_group = group_subprocs.DecayChainSubProcessGroup.\ group_amplitudes(\ diagram_generation.DecayChainAmplitudeList([decay_chains])) subproc_groups = \ dc_subproc_group.generate_helas_decay_chain_subproc_groups() ###################### ## Make the test!! ## ###################### self.assertEqual(len(subproc_groups), 1) subproc_groups = subproc_groups.split_lepton_grouping() self.assertEqual(len(subproc_groups), 2) # check that indeed for group in subproc_groups: self.assertEqual(len(group['matrix_elements']), 2) has_muon = any( abs(l['id']) == 13 for l in group['matrix_elements'][0] ['processes'][0]['decay_chains'][0]['legs']) for me in group['matrix_elements']: if abs(me['processes'][0]['legs'][0]['id']) == 1: self.assertEqual(len(me['processes']), 1) else: self.assertEqual(len(me['processes']), 2) for proc in me['processes']: for dec in proc['decay_chains']: if has_muon: self.assertFalse( any(abs(l['id']) == 11 for l in dec['legs'])) else: self.assertFalse( any(abs(l['id']) == 13 for l in dec['legs'])) self.assertNotEqual(group['name'], 'qq_z_z_ll') if has_muon: self.assertEqual(group['name'], 'qq_z_z_mummup') else: self.assertEqual(group['name'], 'qq_z_z_emep') group['name']