def __init__(self, start_proc = None, remove_reals = True): """initialization: starts either from an amplitude or a process, then init the needed variables. remove_borns tells if the borns not needed for integration will be removed from the born list (mainly used for testing)""" self.splittings = {} self.reals = [] self.fks_dirs = [] self.leglist = [] self.myorders = {} self.pdg_codes = [] self.colors = [] self.nlegs = 0 self.fks_ipos = [] self.fks_j_from_i = {} self.real_amps = [] self.remove_reals = remove_reals self.nincoming = 0 self.virt_amp = None if not remove_reals in [True, False]: raise fks_common.FKSProcessError(\ 'Not valid type for remove_reals in FKSProcess') if start_proc: if isinstance(start_proc, MG.Process): self.born_proc = fks_common.sort_proc(start_proc) self.born_amp = diagram_generation.Amplitude(self.born_proc) elif isinstance(start_proc, diagram_generation.Amplitude): self.born_proc = fks_common.sort_proc(start_proc.get('process')) self.born_amp = diagram_generation.Amplitude(self.born_proc) else: raise fks_common.FKSProcessError(\ 'Not valid start_proc in FKSProcess') self.born_proc.set('legs_with_decays', MG.LegList()) self.leglist = fks_common.to_fks_legs( self.born_proc['legs'], self.born_proc['model']) self.nlegs = len(self.leglist) self.pdg_codes = [leg.get('id') for leg in self.leglist] self.colors = [leg.get('color') for leg in self.leglist] self.isr = set([leg.get('color') for leg in self.leglist if not leg.get('state')]) != set([1]) self.fsr = set([leg.get('color') for leg in self.leglist if leg.get('state')]) != set([1]) for leg in self.leglist: if not leg['state']: self.nincoming += 1 self.orders = self.born_amp['process']['orders'] # this is for cases in which the user specifies e.g. QED=0 if sum(self.orders.values()) == 0: self.orders = fks_common.find_orders(self.born_amp) self.ndirs = 0 for order in self.born_proc.get('perturbation_couplings'): self.find_reals(order)
def __init__(self, fksrealproc=None, real_me_list = [], real_amp_list =[], **opts): """constructor, starts from a fksrealproc and then calls the initialization for HelasMatrixElement. Sets i/j fks and the permutation. real_me_list and real_amp_list are the lists of pre-generated matrix elements in 1-1 correspondance with the amplitudes""" if fksrealproc != None: self.isfinite = False self.colors = fksrealproc.colors self.charges = fksrealproc.charges self.fks_infos = fksrealproc.fks_infos self.is_to_integrate = fksrealproc.is_to_integrate if len(real_me_list) != len(real_amp_list): raise fks_common.FKSProcessError( 'not same number of amplitudes and matrix elements: %d, %d' % \ (len(real_amp_list), len(real_me_list))) if real_me_list and real_amp_list: self.matrix_element = copy.deepcopy(real_me_list[real_amp_list.index(fksrealproc.amplitude)]) self.matrix_element['processes'] = copy.deepcopy(self.matrix_element['processes']) else: logger.info('generating matrix element...') self.matrix_element = helas_objects.HelasMatrixElement( fksrealproc.amplitude, **opts) #generate the color for the real self.matrix_element.get('color_basis').build( self.matrix_element.get('base_amplitude')) self.matrix_element.set('color_matrix', color_amp.ColorMatrix( self.matrix_element.get('color_basis'))) #self.fks_j_from_i = fksrealproc.find_fks_j_from_i() self.fks_j_from_i = fksrealproc.fks_j_from_i
def get_leg_j(self): #test written """Returns leg corresponding to j fks. An error is raised if the fks_infos list has more than one entry""" if len(self.fks_infos) > 1: raise fks_common.FKSProcessError(\ 'get_leg_j should only be called before combining processes') return self.process.get('legs')[self.fks_infos[0]['j'] - 1]
def find_reals(self, pert_order): """finds the FKS real configurations for a given process""" if range(len(self.leglist)) != [l['number']-1 for l in self.leglist]: raise fks_common.FKSProcessError('Disordered numbers of leglist') for i in self.leglist: i_i = i['number'] - 1 self.reals.append([]) self.splittings[i_i] = fks_common.find_splittings(i, self.born_proc['model'], {}, pert_order) for split in self.splittings[i_i]: self.reals[i_i].append( fks_common.insert_legs(self.leglist, i, split,pert=pert_order))
def find_reals(self, pert_order): """finds the FKS real configurations for a given process""" if list(range(len(self.leglist))) != [l['number']-1 for l in self.leglist]: raise fks_common.FKSProcessError('Disordered numbers of leglist') if [ i['state'] for i in self.leglist].count(False) == 1: decay_process=True else: decay_process=False for i in self.leglist: i_i = i['number'] - 1 self.reals.append([]) if decay_process and not i['state']: self.splittings[i_i]=[] else: self.splittings[i_i] = fks_common.find_splittings(i, self.born_proc['model'], {}, pert_order) for split in self.splittings[i_i]: self.reals[i_i].append( fks_common.insert_legs(self.leglist, i, split,pert=pert_order))
def __init__(self, procdef=None, 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) # OLP option olp='MadLoop' if 'OLP' in list(options.keys()): olp = options['OLP'] del options['OLP'] ncores_for_proc_gen = 0 # ncores_for_proc_gen has the following meaning # 0 : do things the old way # > 0 use ncores_for_proc_gen # -1 : use all cores if 'ncores_for_proc_gen' in list(options.keys()): ncores_for_proc_gen = options['ncores_for_proc_gen'] del options['ncores_for_proc_gen'] try: # Now generating the borns for the first time. super(FKSMultiProcess, self).__init__(procdef, **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.") self['OLP'] = olp self['ncores_for_proc_gen'] = ncores_for_proc_gen #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, ncores_for_proc_gen = self['ncores_for_proc_gen']) self['born_processes'].append(born) born.generate_reals(self['pdgs'], self['real_amplitudes']) if not self['ncores_for_proc_gen']: # old generation mode 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 find_reals_to_integrate(self): #test written """Finds double countings in the real emission configurations, sets the is_to_integrate variable and if "self.remove_reals" is True removes the not needed ones from the born list. """ #find the initial number of real configurations ninit = len(self.real_amps) remove = self.remove_reals for m in range(ninit): for n in range(m + 1, ninit): real_m = self.real_amps[m] real_n = self.real_amps[n] if len(real_m.fks_infos) > 1 or len(real_m.fks_infos) > 1: raise fks_common.FKSProcessError(\ 'find_reals_to_integrate should only be called before combining processes') i_m = real_m.fks_infos[0]['i'] j_m = real_m.fks_infos[0]['j'] i_n = real_n.fks_infos[0]['i'] j_n = real_n.fks_infos[0]['j'] if j_m > self.nincoming and j_n > self.nincoming: if (real_m.get_leg_i()['id'] == real_n.get_leg_i()['id'] \ and \ real_m.get_leg_j()['id'] == real_n.get_leg_j()['id']) \ or \ (real_m.get_leg_i()['id'] == real_n.get_leg_j()['id'] \ and \ real_m.get_leg_j()['id'] == real_n.get_leg_i()['id']): if i_m > i_n: print(real_m.get_leg_i()['id'], real_m.get_leg_j()['id']) if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']: self.real_amps[m].is_to_integrate = False else: self.real_amps[n].is_to_integrate = False elif i_m == i_n and j_m > j_n: print(real_m.get_leg_i()['id'], real_m.get_leg_j()['id']) if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']: self.real_amps[m].is_to_integrate = False else: self.real_amps[n].is_to_integrate = False # in case of g(a) > ffx splitting, keep the lowest ij elif i_m == i_n and j_m == j_n and \ not real_m.get_leg_j()['self_antipart'] and \ not real_m.get_leg_i()['self_antipart']: if real_m.fks_infos[0]['ij'] > real_n.fks_infos[0]['ij']: real_m.is_to_integrate = False else: real_n.is_to_integrate = False else: if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']: self.real_amps[n].is_to_integrate = False else: self.real_amps[m].is_to_integrate = False # self.real_amps[m].is_to_integrate = False elif j_m <= self.nincoming and j_n == j_m: if real_m.get_leg_i()['id'] == real_n.get_leg_i()['id'] and \ real_m.get_leg_j()['id'] == real_n.get_leg_j()['id']: if i_m > i_n: self.real_amps[n].is_to_integrate = False else: self.real_amps[m].is_to_integrate = False if remove: newreal_amps = [] for real in self.real_amps: if real.is_to_integrate: newreal_amps.append(real) self.real_amps = newreal_amps
def __init__(self, start_proc = None, remove_reals = True, ncores_for_proc_gen=0): """initialization: starts either from an amplitude or a process, then init the needed variables. remove_borns tells if the borns not needed for integration will be removed from the born list (mainly used for testing) ncores_for_proc_gen has the following meaning 0 : do things the old way > 0 use ncores_for_proc_gen -1 : use all cores """ self.splittings = {} self.reals = [] self.fks_dirs = [] self.leglist = [] self.myorders = {} self.pdg_codes = [] self.colors = [] # color self.charges = [] # charge self.nlegs = 0 self.fks_ipos = [] self.fks_j_from_i = {} self.real_amps = [] self.remove_reals = remove_reals self.nincoming = 0 self.virt_amp = None self.perturbation = 'QCD' self.ncores_for_proc_gen = ncores_for_proc_gen if not remove_reals in [True, False]: raise fks_common.FKSProcessError(\ 'Not valid type for remove_reals in FKSProcess') if start_proc: if isinstance(start_proc, MG.Process): pertur = start_proc['perturbation_couplings'] if pertur: self.perturbation = sorted(pertur)[0] self.born_proc = fks_common.sort_proc(start_proc,pert = self.perturbation) # filter in Amplitude will legs sorted in bornproc bornproc = copy.copy(self.born_proc) # deepcopy might let T -> array assert bornproc==self.born_proc self.born_amp = diagram_generation.Amplitude(bornproc) elif isinstance(start_proc, diagram_generation.Amplitude): pertur = start_proc.get('process')['perturbation_couplings'] if pertur: self.perturbation = sorted(pertur)[0] self.born_proc = fks_common.sort_proc(start_proc.get('process'),\ pert = self.perturbation) # filter in Amplitude will legs sorted in bornproc bornproc = copy.copy(self.born_proc) assert bornproc == self.born_proc self.born_amp = diagram_generation.Amplitude(bornproc) else: raise fks_common.FKSProcessError(\ 'Not valid start_proc in FKSProcess') self.born_proc.set('legs_with_decays', MG.LegList()) self.leglist = fks_common.to_fks_legs( self.born_proc['legs'], self.born_proc['model']) self.nlegs = len(self.leglist) self.pdg_codes = [leg.get('id') for leg in self.leglist] if self.perturbation == 'QCD': self.colors = [leg.get('color') for leg in self.leglist] # in QCD, charge is irrelevant but impact the combine process ! self.charges = [0. for leg in self.leglist] color = 'color' zero = 1 elif self.perturbation == 'QED': self.colors = [leg.get('color') for leg in self.leglist] self.charges = [leg.get('charge') for leg in self.leglist] color = 'charge' zero = 0. # special treatment of photon is needed ! self.isr = set([leg.get(color) for leg in self.leglist if not leg.get('state')]) != set([zero]) self.fsr = set([leg.get(color) for leg in self.leglist if leg.get('state')]) != set([zero]) for leg in self.leglist: if not leg['state']: self.nincoming += 1 self.orders = self.born_amp['process']['orders'] # this is for cases in which the user specifies e.g. QED=0 if sum(self.orders.values()) == 0: self.orders = fks_common.find_orders(self.born_amp) self.ndirs = 0 # generate reals, when the mode is not LOonly # when is LOonly it is supposed to be a 'fake' NLO process # e.g. to be used in merged sampels at high multiplicities if self.born_proc['NLO_mode'] != 'LOonly': for order in self.born_proc.get('perturbation_couplings'): self.find_reals(order)