def test_set_color_links(self): """tests that the set_color_links of a FKSHelasProcess returns the correct list of color_links.""" #ug> ug fks1 = fks_base.FKSProcess(self.myproc1) #ug>gu fks1_qed = fks_base.FKSProcess(self.myproc1_qed) me_list = [] me_list_qed = [] me_id_list = [] me_id_list_qed = [] pdg_list1 = [] pdg_list1_qed = [] real_amp_list1 = diagram_generation.AmplitudeList() real_amp_list1_qed = diagram_generation.AmplitudeList() fks1.generate_reals(pdg_list1, real_amp_list1) fks1_qed.generate_reals(pdg_list1_qed, real_amp_list1_qed) helas_born_proc = fks_helas.FKSHelasProcess(fks1, me_list, me_id_list) helas_born_proc_qed = fks_helas.FKSHelasProcess(\ fks1_qed,me_list_qed,me_id_list_qed) helas_born_proc.set_color_links() helas_born_proc_qed.set_color_links() legpair = [link['link'] for link in helas_born_proc.color_links] legpair_qed = [ link['link'] for link in helas_born_proc_qed.color_links ] tar_legpair = [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] tar_legpair_qed = [[1, 4]] self.assertEqual(legpair, tar_legpair) self.assertEqual(legpair_qed, tar_legpair_qed)
def test_fks_helas_process_init(self): """tests the correct initialization of a FKSHelasProcess object. in particular checks: -- born ME -- list of FKSHelasRealProcesses -- color links -- fks_infos """ #ug> ug fks1 = fks_base.FKSProcess(self.myproc1) #uu~> dd~ fks3 = fks_base.FKSProcess(self.myproc3) pdg_list1 = [] real_amp_list1 = diagram_generation.AmplitudeList() pdg_list3 = [] real_amp_list3 = diagram_generation.AmplitudeList() fks1.generate_reals(pdg_list1, real_amp_list1) fks3.generate_reals(pdg_list3, real_amp_list3) me_list = [] me_id_list = [] me_list3 = [] me_id_list3 = [] res_me_list = [] res_me_id_list = [] helas_born_proc = fks_helas.FKSHelasProcess(fks1, me_list, me_id_list) helas_born_proc3 = fks_helas.FKSHelasProcess(fks3, me_list3, me_id_list3) self.assertEqual(helas_born_proc.born_matrix_element, helas_objects.HelasMatrixElement(fks1.born_amp)) res_reals = [] for real in fks1.real_amps: res_reals.append( fks_helas.FKSHelasRealProcess(real, res_me_list, res_me_id_list)) # the process u g > u g g corresponds to 4 fks configs if real.pdgs == array.array('i', [2, 21, 2, 21, 21]): self.assertEqual(len(real.fks_infos), 4) else: # any other process has only 1 fks config self.assertEqual(len(real.fks_infos), 1) self.assertEqual(me_list, res_me_list) self.assertEqual(me_id_list, res_me_id_list) self.assertEqual(8, len(helas_born_proc.real_processes)) self.assertNotEqual(helas_born_proc.born_matrix_element, helas_born_proc3.born_matrix_element) for a, b in zip(helas_born_proc3.real_processes, helas_born_proc.real_processes): self.assertNotEqual(a, b)
def group_amplitudes(amplitudes, criteria='madevent', matrix_elements_opts={}): """Return a SubProcessGroupList with the amplitudes divided into subprocess groups""" assert isinstance(amplitudes, diagram_generation.AmplitudeList), \ "Argument to group_amplitudes must be AmplitudeList" if not criteria: criteria = 'madevent' assert criteria in ['madevent', 'madweight'] logger.info("Organizing processes into subprocess groups") process_classes = SubProcessGroup.find_process_classes(amplitudes,criteria) ret_list = SubProcessGroupList() process_class_numbers = sorted(list(set(process_classes.values()))) for num in process_class_numbers: amp_nums = [key for (key, val) in process_classes.items() if \ val == num] group = SubProcessGroup({'matrix_element_opts':matrix_elements_opts}) group.set('amplitudes', diagram_generation.AmplitudeList([amplitudes[i] for i in \ amp_nums])) group.set('number', group.get('amplitudes')[0].get('process').\ get('id')) group.set('name', group.generate_name(\ group.get('amplitudes')[0].get('process'), criteria=criteria)) ret_list.append(group) return ret_list
def setup(self): """ Special tasks when switching to this interface """ # Refresh all the interface stored value as things like generated # processes and amplitudes are not to be reused in between different # interfaces # Clear history, amplitudes and matrix elements when a model is imported # Remove previous imports, generations and outputs from history self.history.clean(remove_bef_last='import', to_keep=['set','load','import', 'define']) # Reset amplitudes and matrix elements self._done_export=False self._curr_amps = diagram_generation.AmplitudeList() self._curr_matrix_elements = helas_objects.HelasMultiProcess() self._v4_export_formats = [] self._nlo_modes_for_completion = ['all','real'] self._export_formats = [ 'madevent', 'aloha' ] # Do not force NLO model as the user might have asked for reals only. # It will anyway be forced later if he attempts virt= or all=. self.validate_model(loop_type='real_init', stop=False) # Set where to look for CutTools installation. # In further versions, it will be set in the same manner as _mgme_dir so that # the user can chose its own CutTools distribution. self._cuttools_dir=str(pjoin(self._mgme_dir,'vendor','CutTools')) if not os.path.isdir(pjoin(self._cuttools_dir, 'src','cts')): logger.warning(('Warning: Directory %s is not a valid CutTools directory.'+\ 'Using default CutTools instead.') % \ self._cuttools_dir) self._cuttools_dir=str(pjoin(self._mgme_dir,'vendor','CutTools'))
def generate_matrix_elements(self): """Create a HelasMultiProcess corresponding to the amplitudes in self""" if not self.get('amplitudes'): raise self.PhysicsObjectError, \ "Need amplitudes to generate matrix_elements" amplitudes = copy.copy(self.get('amplitudes')) # The conditional statement tests whether we are dealing with a # loop induced process. We must set compute_loop_nc to True here # since the knowledge of the power of Nc coming from potential # loop color trace is necessary for the loop induced output with MadEvent if isinstance(amplitudes[0], loop_diagram_generation.LoopAmplitude): self.set( 'matrix_elements', loop_helas_objects.LoopHelasProcess.generate_matrix_elements( amplitudes, compute_loop_nc=True, matrix_element_opts=self['matrix_element_opts'])) else: self.set('matrix_elements', helas_objects.HelasMultiProcess.\ generate_matrix_elements(amplitudes)) self.set('amplitudes', diagram_generation.AmplitudeList())
def group_amplitudes(decay_chain_amps, criteria='madevent', matrix_elements_opts={}): """Recursive function. Starting from a DecayChainAmplitude, return a DecayChainSubProcessGroup with the core amplitudes and decay chains divided into subprocess groups""" assert isinstance(decay_chain_amps, diagram_generation.DecayChainAmplitudeList), \ "Argument to group_amplitudes must be DecayChainAmplitudeList" if criteria in ['matrix', 'standalone','pythia8','standalone_cpp', False]: criteria = 'madevent' assert criteria in ['madevent', 'madweight'] # Collect all amplitudes amplitudes = diagram_generation.AmplitudeList() for amp in decay_chain_amps: amplitudes.extend(amp.get('amplitudes')) # Determine core process groups core_groups = SubProcessGroup.group_amplitudes(amplitudes, criteria) dc_subproc_group = DecayChainSubProcessGroup(\ {'core_groups': core_groups, 'decay_chain_amplitudes': decay_chain_amps}) decays = diagram_generation.DecayChainAmplitudeList() # Recursively determine decay chain groups for decay_chain_amp in decay_chain_amps: decays.extend(decay_chain_amp.get('decay_chains')) if decays: dc_subproc_group.get('decay_groups').append(\ DecayChainSubProcessGroup.group_amplitudes(decays, criteria)) return dc_subproc_group
def test_find_symmetry_uu_tt_with_subprocess_group(self): """Test the find_symmetry function for subprocess groups""" procs = [[2,2,6,6]] amplitudes = diagram_generation.AmplitudeList() 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':self.base_model_4ferm}) my_amplitude = diagram_generation.Amplitude(my_process) amplitudes.append(my_amplitude) subproc_group = \ group_subprocs.SubProcessGroup.group_amplitudes(amplitudes, "madevent")[0] symmetry, perms, ident_perms = diagram_symmetry.find_symmetry(\ subproc_group) self.assertEqual(len([s for s in symmetry if s > 0]), 1) self.assertEqual(symmetry, [1]) return
def default_setup(self): """Default values for all properties""" super(FKSMultiProcess, self).default_setup() self['real_amplitudes'] = diagram_generation.AmplitudeList() self['pdgs'] = [] self['born_processes'] = FKSProcessList() if not 'OLP' in list(self.keys()): self['OLP'] = 'MadLoop' self['ncores_for_proc_gen'] = 0
def test_find_symmetry_qq_qqg_with_subprocess_group(self): """Test the find_symmetry function for subprocess groups""" procs = [[2,-2,2,-2,21], [2,2,2,2,21]] amplitudes = diagram_generation.AmplitudeList() 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':self.base_model}) my_amplitude = diagram_generation.Amplitude(my_process) amplitudes.append(my_amplitude) subproc_group = \ group_subprocs.SubProcessGroup.group_amplitudes(amplitudes,"madevent")[0] symmetry, perms, ident_perms = diagram_symmetry.find_symmetry(\ subproc_group) self.assertEqual(len([s for s in symmetry if s > 0]), 19) self.assertEqual(symmetry,[1, 1, 1, 1, -2, -3, -4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -8, -9, -10, -11, -12, -13, -14, -18, -19]) return # The test below doesn't apply with the new way of determining # config symmetry for subprocess groups, since we don't demand # that symmetric diagrams have identical particles. # Check that the momentum assignments work matrix_element = \ subproc_group.get('matrix_elements')[1] process = matrix_element.get('processes')[0] evaluator = process_checks.MatrixElementEvaluator(self.base_model, auth_skipping = True, reuse = True) p, w_rambo = evaluator.get_momenta(process) me_value, amp2_org = evaluator.evaluate_matrix_element(\ matrix_element, p) for isym, (sym, perm) in enumerate(zip(symmetry, perms)): new_p = [p[i] for i in perm] if sym >= 0: continue iamp = subproc_group.get('diagram_maps')[1].index(isym+1) isymamp = subproc_group.get('diagram_maps')[1].index(-sym) me_value, amp2 = evaluator.evaluate_matrix_element(\ matrix_element, new_p) self.assertAlmostEqual(amp2[iamp], amp2_org[isymamp])
def default_setup(self): """Define object and give default values""" self['number'] = 0 self['name'] = "" self['amplitudes'] = diagram_generation.AmplitudeList() self['matrix_elements'] = helas_objects.HelasMatrixElementList() self['mapping_diagrams'] = [] self['diagram_maps'] = {} self['diagrams_for_configs'] = [] self['amplitude_map'] = {}
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 generate_matrix_elements(self): """Create a HelasMultiProcess corresponding to the amplitudes in self""" if not self.get('amplitudes'): raise self.PhysicsObjectError, \ "Need amplitudes to generate matrix_elements" amplitudes = copy.copy(self.get('amplitudes')) self.set('matrix_elements', helas_objects.HelasMultiProcess.\ generate_matrix_elements(amplitudes)) self.set('amplitudes', diagram_generation.AmplitudeList())
def generate_helas_decay_chain_subproc_groups(self): """Combine core_groups and decay_groups to give HelasDecayChainProcesses and new diagram_maps. """ # Combine decays matrix_elements = \ helas_objects.HelasMultiProcess.generate_matrix_elements(\ diagram_generation.AmplitudeList(\ self.get('decay_chain_amplitudes'))) # For each matrix element, check which group it should go into and # calculate diagram_maps me_assignments = {} for me in matrix_elements: group_assignment = self.assign_group_to_decay_process(\ me.get('processes')[0]) assert group_assignment try: me_assignments[group_assignment].append(me) except KeyError: me_assignments[group_assignment] = [me] # Create subprocess groups corresponding to the different # group_assignments subproc_groups = SubProcessGroupList() for key in sorted(me_assignments.keys()): group = SubProcessGroup() group.set('matrix_elements', helas_objects.HelasMatrixElementList(\ me_assignments[key])) group.set('number', group.get('matrix_elements')[0].\ get('processes')[0].get('id')) group.set('name', group.generate_name(\ group.get('matrix_elements')[0].\ get('processes')[0])) subproc_groups.append(group) return subproc_groups
def get_virt_amplitudes(self): """return an amplitudelist with the virt amplitudes""" return diagram_generation.AmplitudeList([born.virt_amp \ for born in self['born_processes'] if born.virt_amp])
def do_display(self, line, output=sys.stdout): # if we arrive here it means that a _fks_display_opts has been chosen args = self.split_arg(line) #check the validity of the arguments self.check_display(args) if args[0] in ['diagrams', 'processes', 'diagrams_text']: get_amps_dict = { 'real': self._fks_multi_proc.get_real_amplitudes, 'born': self._fks_multi_proc.get_born_amplitudes, 'loop': self._fks_multi_proc.get_virt_amplitudes } if args[0] == 'diagrams': if len(args) >= 2 and args[1] in list(get_amps_dict.keys()): get_amps = get_amps_dict[args[1]] self._curr_amps = get_amps() #check that if one requests the virt diagrams, there are virt_amplitudes if args[1] == 'loop' and len(self._curr_amps) == 0: raise self.InvalidCmd( 'No virtuals have been generated') self.draw(' '.join(args[2:]), type=args[1]) else: for diag_type, get_amps in get_amps_dict.items(): self._curr_amps = get_amps() self.draw(' '.join(args[1:]), Dtype=diag_type) # set _curr_amps back to empty self._curr_amps = diagram_generation.AmplitudeList() if args[0] == 'diagrams_text': if len(args) >= 2 and args[1] in list(get_amps_dict.keys()): get_amps = get_amps_dict[args[1]] self._curr_amps = get_amps() #check that if one requests the virt diagrams, there are virt_amplitudes if args[1] in ['virt', 'loop'] and len( self._curr_amps) == 0: raise self.InvalidCmd( 'No virtuals have been generated') text = "\n".join( [amp.nice_string() for amp in self._curr_amps]) else: text = 'Born diagrams:\n' text += '\n'.join(amp.nice_string() for amp in get_amps_dict['born']()) text += '\n\nReal diagrams:' text += '\n'.join(amp.nice_string() for amp in get_amps_dict['real']()) text += '\n\nLoop diagrams:\n' text += '\n'.join(amp.nice_string() for amp in get_amps_dict['loop']()) pydoc.pager(text) # set _curr_amps back to empty self._curr_amps = diagram_generation.AmplitudeList() elif args[0] == 'processes': if len(args) >= 2 and args[1] in list(get_amps_dict.keys()): get_amps = get_amps_dict[args[1]] self._curr_amps = get_amps() #check that if one requests the virt diagrams, there are virt_amplitudes if args[1] in ['virt', 'loop'] and len( self._curr_amps) == 0: raise self.InvalidCmd( 'No virtuals have been generated') print('\n'.join(amp.nice_string_processes() for amp in self._curr_amps)) else: print('Born processes:') print('\n'.join(amp.nice_string_processes() for amp in get_amps_dict['born']())) print('Real processes:') print('\n'.join(amp.nice_string_processes() for amp in get_amps_dict['real']())) print('Loop processes:') print('\n'.join(amp.nice_string_processes() for amp in get_amps_dict['loop']())) # set _curr_amps back to empty self._curr_amps = diagram_generation.AmplitudeList() else: mg_interface.MadGraphCmd.do_display(self, line, output)
def ML5export(self, nojpeg=False, main_file_name=""): """Export a generated amplitude to file""" def generate_matrix_elements(self): """Helper function to generate the matrix elements before exporting""" # Sort amplitudes according to number of diagrams, # to get most efficient multichannel output self._curr_amps.sort(lambda a1, a2: a2.get_number_of_diagrams() - \ a1.get_number_of_diagrams()) cpu_time1 = time.time() ndiags = 0 if not self._curr_matrix_elements.get_matrix_elements(): self._curr_matrix_elements = \ loop_helas_objects.LoopHelasProcess(self._curr_amps, optimized_output = self.options['loop_optimized_output']) ndiags = sum([len(me.get('diagrams')) for \ me in self._curr_matrix_elements.\ get_matrix_elements()]) # assign a unique id number to all process uid = 0 for me in self._curr_matrix_elements.get_matrix_elements(): uid += 1 # update the identification number me.get('processes')[0].set('uid', uid) cpu_time2 = time.time() return ndiags, cpu_time2 - cpu_time1 # Start of the actual routine ndiags, cpu_time = generate_matrix_elements(self) calls = 0 path = self._export_dir if self._export_format in self.supported_ML_format: path = pjoin(path, 'SubProcesses') cpu_time1 = time.time() # Pick out the matrix elements in a list matrix_elements = \ self._curr_matrix_elements.get_matrix_elements() # Fortran MadGraph5_aMC@NLO Standalone if self._export_format in self.supported_ML_format: for me in matrix_elements: calls = calls + \ self._curr_exporter.generate_subprocess_directory_v4(\ me, self._curr_fortran_model) # If all ME's do not share the same maximum loop vertex rank and the # same loop maximum wavefunction size, we need to set the maximum # in coef_specs.inc of the HELAS Source. The SubProcesses/P* directory # all link this file, so it should be properly propagated if self.options['loop_optimized_output'] and len( matrix_elements) > 1: max_lwfspins = [m.get_max_loop_particle_spin() for m in \ matrix_elements] max_loop_vert_ranks = [me.get_max_loop_vertex_rank() for me in \ matrix_elements] if len(set(max_lwfspins)) > 1 or len( set(max_loop_vert_ranks)) > 1: self._curr_exporter.fix_coef_specs(max(max_lwfspins),\ max(max_loop_vert_ranks)) # Just the matrix.f files if self._export_format == 'matrix': for me in matrix_elements: filename = pjoin(path, 'matrix_' + \ me.get('processes')[0].shell_string() + ".f") if os.path.isfile(filename): logger.warning("Overwriting existing file %s" % filename) else: logger.info("Creating new file %s" % filename) calls = calls + self._curr_exporter.write_matrix_element_v4(\ writers.FortranWriter(filename),\ me, self._curr_fortran_model) cpu_time2 = time.time() - cpu_time1 logger.info(("Generated helas calls for %d subprocesses " + \ "(%d diagrams) in %0.3f s") % \ (len(matrix_elements), ndiags, cpu_time)) if calls: if "cpu_time2" in locals(): logger.info("Wrote files for %d OPP calls in %0.3f s" % \ (calls, cpu_time2)) else: logger.info("Wrote files for %d OPP calls" % \ (calls)) # Replace the amplitudes with the actual amplitudes from the # matrix elements, which allows proper diagram drawing also of # decay chain processes self._curr_amps = diagram_generation.AmplitudeList(\ [me.get('base_amplitude') for me in \ matrix_elements])
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 test_export_matrix_element_python_madevent_group(self): """Test the result of exporting a subprocess group matrix element""" # Setup a model mypartlist = base_objects.ParticleList() myinterlist = base_objects.InteractionList() # A gluon mypartlist.append( base_objects.Particle({ 'name': 'g', 'antiname': 'g', 'spin': 3, 'color': 8, 'mass': 'zero', 'width': 'zero', 'texname': 'g', 'antitexname': 'g', 'line': 'curly', 'charge': 0., 'pdg_code': 21, 'propagating': True, 'is_part': True, 'self_antipart': True })) g = mypartlist[-1] # 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 photon mypartlist.append( base_objects.Particle({ 'name': 'a', 'antiname': 'a', 'spin': 3, 'color': 1, 'mass': 'zero', 'width': 'zero', 'texname': '\gamma', 'antitexname': '\gamma', 'line': 'wavy', 'charge': 0., 'pdg_code': 22, 'propagating': True, 'is_part': True, 'self_antipart': True })) a = mypartlist[-1] # 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] # Gluon and photon couplings to quarks myinterlist.append(base_objects.Interaction({ 'id': 1, 'particles': base_objects.ParticleList(\ [antiu, \ u, \ g]), 'color': [], 'lorentz':['L1'], 'couplings':{(0, 0):'GQQ'}, 'orders':{'QCD':1}})) myinterlist.append(base_objects.Interaction({ 'id': 2, 'particles': base_objects.ParticleList(\ [antiu, \ u, \ a]), 'color': [], 'lorentz':['L1'], 'couplings':{(0, 0):'GQED'}, 'orders':{'QED':1}})) myinterlist.append(base_objects.Interaction({ 'id': 3, 'particles': base_objects.ParticleList(\ [antid, \ d, \ g]), 'color': [], 'lorentz':['L1'], 'couplings':{(0, 0):'GQQ'}, 'orders':{'QCD':1}})) myinterlist.append(base_objects.Interaction({ 'id': 4, 'particles': base_objects.ParticleList(\ [antid, \ d, \ a]), 'color': [], 'lorentz':['L1'], 'couplings':{(0, 0):'GQED'}, 'orders':{'QED':1}})) # 3 gluon vertiex myinterlist.append(base_objects.Interaction({ 'id': 5, 'particles': base_objects.ParticleList(\ [g] * 3), 'color': [], 'lorentz':['L1'], 'couplings':{(0, 0):'G'}, 'orders':{'QCD':1}})) # Coupling of Z to quarks myinterlist.append(base_objects.Interaction({ 'id': 6, 'particles': base_objects.ParticleList(\ [antiu, \ u, \ z]), 'color': [], 'lorentz':['L1', 'L2'], 'couplings':{(0, 0):'GUZ1', (0, 1):'GUZ2'}, 'orders':{'QED':1}})) myinterlist.append(base_objects.Interaction({ 'id': 7, 'particles': base_objects.ParticleList(\ [antid, \ d, \ z]), 'color': [], 'lorentz':['L1', 'L2'], 'couplings':{(0, 0):'GDZ1', (0, 0):'GDZ2'}, 'orders':{'QED':1}})) mymodel = base_objects.Model() mymodel.set('particles', mypartlist) mymodel.set('interactions', myinterlist) procs = [[2, -2, 21, 21], [2, -2, 2, -2]] amplitudes = diagram_generation.AmplitudeList() 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) amplitudes.append(my_amplitude) # Calculate diagrams for all processes subprocess_group = group_subprocs.SubProcessGroup.\ group_amplitudes(amplitudes, "madevent")[0] # Test amp2 lines helas_writer = helas_call_writers.PythonUFOHelasCallWriter(mymodel) python_exporter = export_python.ProcessExporterPython( subprocess_group, helas_writer) amp2_lines = \ python_exporter.get_amp2_lines(subprocess_group.\ get('matrix_elements')[0], subprocess_group.get('diagram_maps')[0]) self.assertEqual(amp2_lines, [ 'self.amp2[0]+=abs(amp[0]*amp[0].conjugate())', 'self.amp2[1]+=abs(amp[1]*amp[1].conjugate())', 'self.amp2[2]+=abs(amp[2]*amp[2].conjugate())' ])
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']
def test_get_fks_info_list(self): """tests that the get_fks_info_list of a FKSHelasProcess returns the correct list of configurations/fks_configs""" #ug> ug fks1 = fks_base.FKSProcess(self.myproc1) me_list = [] me_id_list = [] pdg_list1 = [] real_amp_list1 = diagram_generation.AmplitudeList() fks1.generate_reals(pdg_list1, real_amp_list1) helas_born_proc = fks_helas.FKSHelasProcess(fks1, me_list, me_id_list) goal = \ [ {'n_me' : 1, 'pdgs':[2,21,2,21,21], \ 'fks_info': {'i':5, 'j':1, 'ij':1, 'ij_glu':0, 'need_color_links':True, 'rb_links': [{'born_conf': 0, 'real_conf': 11}, {'born_conf': 1, 'real_conf': 10}, {'born_conf': 2, 'real_conf': 9}]}}, {'n_me' : 1, 'pdgs':[2,21,2,21,21], \ 'fks_info': {'i':5, 'j':2, 'ij':2, 'ij_glu':2, 'need_color_links':True, 'rb_links': [{'born_conf': 0, 'real_conf': 14}, {'born_conf': 1, 'real_conf': 4}, {'born_conf': 2, 'real_conf': 7}]}}, {'n_me' : 1, 'pdgs':[2,21,2,21,21], \ 'fks_info': {'i':5, 'j':3, 'ij':3, 'ij_glu':0, 'need_color_links':True, 'rb_links': [{'born_conf': 0, 'real_conf': 1}, {'born_conf': 1, 'real_conf': 13}, {'born_conf': 2, 'real_conf': 8}]}}, {'n_me' : 1, 'pdgs':[2,21,2,21,21], \ 'fks_info': {'i':5, 'j':4, 'ij':4, 'ij_glu':4, 'need_color_links':True, 'rb_links': [{'born_conf': 0, 'real_conf': 2}, {'born_conf': 1, 'real_conf': 5}, {'born_conf': 2, 'real_conf': 12}]}}, {'n_me' : 2, 'pdgs':[21,21,2,-2,21], \ 'fks_info': {'i':4, 'j':1, 'ij':1, 'ij_glu':0, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 8}, {'born_conf': 1, 'real_conf': 7}, {'born_conf': 2, 'real_conf': 6}]}}, {'n_me' : 3, 'pdgs':[2,-1,2,-1,21], \ 'fks_info': {'i':4, 'j':2, 'ij':2, 'ij_glu':2, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 4}, {'born_conf': 1, 'real_conf': 0}, {'born_conf': 2, 'real_conf': 3}]}}, {'n_me' : 4, 'pdgs':[2,1,2,1,21], \ 'fks_info': {'i':4, 'j':2, 'ij':2, 'ij_glu':2, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 4}, {'born_conf': 1, 'real_conf': 0}, {'born_conf': 2, 'real_conf': 3}]}}, {'n_me' : 5, 'pdgs':[2,-2,2,-2,21], \ 'fks_info': {'i':4, 'j':2, 'ij':2, 'ij_glu':2, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 8}, {'born_conf': 1, 'real_conf': 3}, {'born_conf': 2, 'real_conf': 6}]}}, {'n_me' : 6, 'pdgs':[2,2,2,2,21], \ 'fks_info': {'i':4, 'j':2, 'ij':2, 'ij_glu':2, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 9}, {'born_conf': 1, 'real_conf': 0}, {'born_conf': 2, 'real_conf': 7}]}}, {'n_me' : 7, 'pdgs':[2,21,2,1,-1], \ 'fks_info': {'i':5, 'j':4, 'ij':4, 'ij_glu':4, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 0}, {'born_conf': 1, 'real_conf': 3}, {'born_conf': 2, 'real_conf': 4}]}}, {'n_me' : 8, 'pdgs':[2,21,2,2,-2], \ 'fks_info': {'i':5, 'j':4, 'ij':4, 'ij_glu':4, 'need_color_links':False, 'rb_links': [{'born_conf': 0, 'real_conf': 1}, {'born_conf': 1, 'real_conf': 4}, {'born_conf': 2, 'real_conf': 8}]}}, ] for a, b in zip(goal, helas_born_proc.get_fks_info_list()): self.assertEqual(a, b) self.assertEqual(goal, helas_born_proc.get_fks_info_list())
def __init__(self, *arguments, **options): """Initializes the original multiprocess, then generates the amps for the borns, then generate the born processes and the reals. Real amplitudes are stored in real_amplitudes according on the pdgs of their legs (stored in pdgs, so that they need to be generated only once and then reicycled """ #swhich the other loggers off loggers_off = [ logging.getLogger('madgraph.diagram_generation'), logging.getLogger('madgraph.loop_diagram_generation') ] old_levels = [logg.level for logg in loggers_off] for logg in loggers_off: logg.setLevel(logging.WARNING) self['real_amplitudes'] = diagram_generation.AmplitudeList() self['pdgs'] = [] if 'OLP' in options.keys(): self['OLP'] = options['OLP'] del options['OLP'] try: # Now generating the borns for the first time. super(FKSMultiProcess, self).__init__(*arguments, **options) except diagram_generation.NoDiagramException as error: # If no born, then this process most likely does not have any. raise NoBornException, "Born diagrams could not be generated for the "+\ self['process_definitions'][0].nice_string().replace('Process',\ 'process')+". Notice that aMC@NLO does not handle loop-induced"+\ " processes yet, but you can still use MadLoop if you want to "+\ "only generate them."+\ " For this, use the 'virt=' mode, without multiparticle labels." #check limitation of FKS if arguments and isinstance(arguments, MG.Process): myprocdef = arguments[0] misc.sprint(myprocdef.keys()) if myprocdef['perturbation_couplings'] != ['QCD']: raise InvalidCmd("FKS for reals only available in QCD for now, you asked %s" \ % ', '.join(myprocdef['perturbation_couplings'])) elif myprocdef.get_ninitial() == 1: raise InvalidCmd("At this stage aMC@NLO cannot handle decay process.\n"+\ " Only Leading Order (loop-induced and tree level) decay are supported.") #check process definition(s): # a process such as g g > g g will lead to real emissions # (e.g: u g > u g g ) which will miss some corresponding born, # leading to non finite results perturbation = [] for procdef in self['process_definitions']: soft_particles = [] # do not warn for decay processes if [i['state'] for i in procdef['legs']].count(False) == 1: continue for pert in procdef['perturbation_couplings']: if pert not in perturbation: perturbation.append(pert) soft_particles.extend(\ fks_common.find_pert_particles_interactions(\ procdef['model'], pert)['soft_particles']) soft_particles_string = ', '.join( \ [procdef['model'].get('particle_dict')[id][\ {True:'name', False:'antiname'}[id >0] ] \ for id in sorted(soft_particles, reverse=True)]) for leg in procdef['legs']: if any([id in soft_particles for id in leg['ids']]) \ and sorted(leg['ids']) != soft_particles: logger.warning(('%s can have real emission processes ' + \ 'which are not finite.\nTo avoid this, please use multiparticles ' + \ 'when generating the process and be sure to include all the following ' + \ 'particles in the multiparticle definition:\n %s' ) \ % (procdef.nice_string(), soft_particles_string) ) break for procdef in self['process_definitions']: procdef.set( 'orders', diagram_generation.MultiProcess.find_optimal_process_orders( procdef)) amps = self.get('amplitudes') for i, amp in enumerate(amps): logger.info("Generating FKS-subtracted matrix elements for born process%s (%d / %d)" \ % (amp['process'].nice_string(print_weighted=False).replace(\ 'Process', ''), i + 1, len(amps))) born = FKSProcess(amp) self['born_processes'].append(born) born.generate_reals(self['pdgs'], self['real_amplitudes']) born_pdg_list = [[l['id'] for l in born.born_proc['legs']] \ for born in self['born_processes'] ] for born in self['born_processes']: for real in born.real_amps: real.find_fks_j_from_i(born_pdg_list) if amps: if self['process_definitions'][0].get('NLO_mode') == 'all': self.generate_virtuals() elif not self['process_definitions'][0].get('NLO_mode') in [ 'all', 'real', 'LOonly' ]: raise fks_common.FKSProcessError(\ "Not a valid NLO_mode for a FKSMultiProcess: %s" % \ self['process_definitions'][0].get('NLO_mode')) # now get the total number of diagrams n_diag_born = sum([ len(amp.get('diagrams')) for amp in self.get_born_amplitudes() ]) n_diag_real = sum([ len(amp.get('diagrams')) for amp in self.get_real_amplitudes() ]) n_diag_virt = sum([ len(amp.get('loop_diagrams')) for amp in self.get_virt_amplitudes() ]) if n_diag_virt == 0 and n_diag_real ==0 and \ not self['process_definitions'][0].get('NLO_mode') == 'LOonly': raise fks_common.FKSProcessError( 'This process does not have any correction up to NLO in %s'\ %','.join(perturbation)) logger.info(('Generated %d subprocesses with %d real emission diagrams, ' + \ '%d born diagrams and %d virtual diagrams') % \ (len(self['born_processes']), n_diag_real, n_diag_born, n_diag_virt)) for i, logg in enumerate(loggers_off): logg.setLevel(old_levels[i]) self['has_isr'] = any([proc.isr for proc in self['born_processes']]) self['has_fsr'] = any([proc.fsr for proc in self['born_processes']])
def get_born_amplitudes(self): """return an amplitudelist with the born amplitudes""" return diagram_generation.AmplitudeList([born.born_amp \ for born in self['born_processes']])