class QCD_initial_collinear_0_qq(QCD_initial_collinear_0_XX): """qq collinear ISR tree-level current. g(initial) > q(initial_after_emission) qx(final)""" # Make sure to have the initial particle with the lowest index structure = [ sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, 21, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, +1, sub.SubtractionLeg.FINAL), )), sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, 21, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, -1, sub.SubtractionLeg.FINAL), )) ] # Below is an example on how to efficiently debug 'does_implement_this_current' # @classmethod # def does_implement_this_current(cls, current, model): # # res = super(QCD_initial_collinear_0_qq, cls).does_implement_this_current(current, model) # # misc.sprint("For this structure: %s"%current.get('singular_structure').__str__(print_n=True, print_pdg=True, print_state=True, sort=True)) # misc.sprint("I get:",res) # import pdb # pdb.set_trace() def kernel(self, evaluation, parent, xs, kTs): # Retrieve the collinear variable x x = xs[0] # The factor 'x' that should be part of the initial_state_crossing_factor cancels # against the extra prefactor 1/x in the collinear factorization formula # (see Eq. (8) of NNLO compatible NLO scheme publication arXiv:0903.1218v2) initial_state_crossing_factor = -1. # Correct for the ratio of color-averaging factor between the real ME # initial state flavor (gluon) and the one of the reduced Born ME (quark) initial_state_crossing_factor *= (self.NC / float(self.NC**2 - 1)) z = 1. / x norm = initial_state_crossing_factor * self.CF # We re-use here the Altarelli-Parisi Kernel of the P_gq final state kernel evaluation['values'][(0, 0, 0)] = { 'finite': norm * ((1. + (1. - z)**2) / z) } return evaluation
class QCD_final_collinear_0_gq(QCD_final_collinear_with_soft): """g q collinear tree-level current. This contains - the hard-collinear kernel for g(0)q(1) being collinear - the pieces of the eikonal terms for g(0) soft emitted from q(1)X(j) which also diverge in the g(0)q(1) collinear limit """ structure = sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(1, +1, sub.SubtractionLeg.FINAL), )) def kernel(self, zs, kTs, parent, reduced_kinematics): # Retrieve the collinear variables z = zs[0] # Instantiate the structure of the result evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [None], 'color_correlations': [None], 'reduced_kinematics': [reduced_kinematics], 'values': { (0, 0, 0): { 'finite': None } } }) # Compute the kernel using # f9d0839fc58905d67367e3e67efabee05ee390f9:madgraph/iolibs/template_files/OLD_subtraction/cataniseymour/NLO/local_currents.py:146 evaluation['values'][(0, 0, 0)]['finite'] = \ self.CF*z return evaluation
class QCD_final_collinear_0_qqx(QCD_final_collinear_0_XX): """q q~ collinear tree-level current.""" structure = sub.SingularStructure(sub.CollStructure( sub.SubtractionLeg(0, +1, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(1, -1, sub.SubtractionLeg.FINAL), )) def kernel(self, evaluation, parent, zs, kTs): # Retrieve the collinear variables z = zs[0] kT = kTs[0] # Instantiate the structure of the result evaluation['spin_correlations'] = [None, ((parent, (kT,)),), ] # Compute the kernel # The line below implements the g_{\mu\nu} part of the splitting kernel. # Notice that the extra longitudinal terms included in the spin-correlation 'None' # from the relation: # \sum_\lambda \epsilon_\lambda^\mu \epsilon_\lambda^{\star\nu} # = g^{\mu\nu} + longitudinal terms # are irrelevant because Ward identities evaluate them to zero anyway. evaluation['values'][(0, 0, 0)] = { 'finite' : self.TR } evaluation['values'][(1, 0, 0)] = { 'finite' : 4 * self.TR * z * (1-z) / kT.square() } return evaluation
class QCD_final_collinear_0_qqpqp(QCD_final_collinear_0_XXX): """qg collinear FSR tree-level current. q(final) > q(final) q'(final) qbar' (final) """ # Make sure to have the initial particle with the lowest index structure = [ sub.SingularStructure(sub.CollStructure( sub.SubtractionLeg(0, +1, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(1, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(2, -2, sub.SubtractionLeg.FINAL), )), ] def kernel(self, evaluation, parent, variables): # Retrieve the collinear variable x z_i, z_r, z_s = variables['zs'] kT_i, kT_r, kT_s = variables['kTs'] s_ir, s_is, s_rs = variables['ss'][(0,1)], variables['ss'][(0,2)], variables['ss'][(1,2)] for spin_correlation_vector, weight in AltarelliParisiKernels.P_qqpqp(self, z_i, z_r, z_s, s_ir, s_is, s_rs, kT_i, kT_r, kT_s ): complete_weight = weight if spin_correlation_vector is None: evaluation['values'][(0, 0, 0)] = {'finite': complete_weight[0]} else: evaluation['spin_correlations'].append((parent, spin_correlation_vector)) evaluation['values'][(len(evaluation['spin_correlations'])-1, 0, 0)] = {'finite': complete_weight[0]} return evaluation
def get_intermediate_PS_point(self, higher_PS_point, children): recoilers = tuple(i for i in higher_PS_point.keys() if i not in (1, 2, children[0], children[1])) def dummy_leg(i): return subtraction.SubtractionLeg(i, 21, subtraction.SubtractionLeg.FINAL) structure = subtraction.SingularStructure(substructures=[ subtraction.CollStructure(legs=(dummy_leg(children[0]), dummy_leg(children[1]))), ], legs=(dummy_leg(r) for r in recoilers)) leg_numbers_map = subtraction.bidict({ i: frozenset({ i, }) for i in higher_PS_point.keys() if i not in (children[0], children[1]) }) leg_numbers_map[1000] = frozenset({children[0], children[1]}) mapping = mappings.FinalGroupingMapping intermediate_ps_point, mapping_vars = mapping.map_to_lower_multiplicity( higher_PS_point, structure, leg_numbers_map) return intermediate_ps_point, mapping_vars
class QCD_initial_collinear_0_gq(QCD_initial_collinear_0_XX): """gq collinear ISR tree-level current. q(initial) > g(initial_after_emission) q(final)""" # Make sure to have the initial particle with the lowest index structure = [ sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, +1, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, +1, sub.SubtractionLeg.FINAL), )), sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, -1, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, -1, sub.SubtractionLeg.FINAL), )), ] def kernel(self, evaluation, parent, xs, kTs): # Retrieve the collinear variable x x = xs[0] kT = kTs[0] # Set spin correlations evaluation['spin_correlations'] = [ None, ((parent, (kT, )), ), ] # The factor 'x' that should be part of the initial_state_crossing_factor cancels # against the extra prefactor 1/x in the collinear factorization formula # (see Eq. (8) of NNLO compatible NLO scheme publication arXiv:0903.1218v2) initial_state_crossing_factor = -1. # Correct for the ratio of color-averaging factor between the real ME # initial state flavor (quark) and the one of the reduced Born ME (gluon) initial_state_crossing_factor *= (self.NC**2 - 1) / float(self.NC) z = 1. / x norm = initial_state_crossing_factor * self.TR # We re-use here the Altarelli-Parisi Kernel of the P_q\bar{q} final state kernel evaluation['values'][(0, 0, 0)] = {'finite': norm} evaluation['values'][(1, 0, 0)] = { 'finite': 4. * norm * z * (1. - z) / kT.square() } return evaluation
def approach_limit(self, PS_point, structure, scaling_parameter, process): """Produce a higher multiplicity phase-space point from PS_point, according to kinematic_variables that approach the limit of structure parametrically with scaling_parameter. """ # Decompose the counterterm decomposed = structure.decompose() # The rescaling of the convolution variables is done independently of the mapping # and should therefore not be considered decomposed = [step for step in decomposed if step.name() != "F"] # Always approach the limit at the same speed base = scaling_parameter**(1. / max(len(decomposed), 1)) #base = scaling_parameter # Prepare a momentum dictionary for each mapping mom_dict = sub.bidict() for leg in process['legs']: mom_dict[leg['number']] = frozenset([ leg['number'], ]) parent_index = max(leg['number'] for leg in process['legs']) + 1 fake_ct = sub.Counterterm(process=process, momenta_dict=mom_dict) closer_PS_point = PS_point.get_copy() # Walk the hike up and down for step in decomposed: mapping = self.determine_mapping(step) all_children = frozenset([leg.n for leg in step.get_all_legs()]) recoilers = self.get_recoilers(fake_ct, exclude=all_children) # Below is a hack to recoil against the Higgs for C(1,3),C(2,4) of g g > d d~ h. #recoilers = [sub.SubtractionLeg(5,25,sub.SubtractionLeg.FINAL),] new_ss = sub.SingularStructure(substructures=[ step, ], legs=recoilers) if step.name() == "C": mom_dict[parent_index] = all_children elif step.name() == "S": pass else: raise MadGraph5Error("Unrecognized structure of type " + step.name()) kin_variables = {} #misc.sprint('Now doing step: %s'%str(step)) #misc.sprint('Starting PS point:\n',str(closer_PS_point)) low_PS_point, _ = mapping.map_to_lower_multiplicity( closer_PS_point, new_ss, mom_dict, None, kin_variables) #misc.sprint('Mapped down PS point:\n',str(low_PS_point)) #misc.sprint('kin_variables=',kin_variables) mapping.rescale_kinematic_variables(new_ss, mom_dict, kin_variables, base) #misc.sprint('rescaled kin_variables=',base,kin_variables) closer_PS_point, _ = mapping.map_to_higher_multiplicity( low_PS_point, new_ss, mom_dict, kin_variables) #misc.sprint('Mapped up PS point:\n',str(closer_PS_point)) #misc.sprint('kin_variables=',kin_variables) if parent_index in mom_dict.keys(): del mom_dict[parent_index] return closer_PS_point
class QCD_soft_0_qqp(QCD_soft_0_kX): """Soft quark-anti quark pair. """ structure = sub.SingularStructure(substructures=(sub.SoftStructure( legs=( sub.SubtractionLeg(10, +1, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -1, sub.SubtractionLeg.FINAL), ) ),) ) soft_kernel = staticmethod(SoftKernels.qqx)
class QCD_initial_collinear_0_qg(QCD_initial_collinear_0_XX): """qg collinear ISR tree-level current. q(initial) > q(initial_after_emission) g(final)""" # Make sure to have the initial particle with the lowest index structure = [ sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, +1, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), )), sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, -1, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), )), ] def kernel(self, evaluation, parent, xs, kTs): # Retrieve the collinear variable x x = xs[0] # The factor 'x' that should be part of the initial_state_crossing_factor cancels # against the extra prefactor 1/x in the collinear factorization formula # (see Eq. (8) of NNLO compatible NLO scheme publication arXiv:0903.1218v2) initial_state_crossing_factor = 1. # Correct for the ratio of color-averaging factor between the real ME # initial state flavor (quark) and the one of the reduced Born ME (quark) initial_state_crossing_factor *= 1. z = 1. / x norm = initial_state_crossing_factor * self.CF # We re-use here the Altarelli-Parisi Kernel of the P_qg final state kernel evaluation['values'][(0, 0, 0)] = { 'finite': norm * ((1. + z**2) / (1. - z)) } return evaluation
class QCD_initial_collinear_0_gg(QCD_initial_collinear_0_XX): """gg collinear ISR tree-level current. g(initial) > g(initial_after_emission) g(final)""" # Make sure to have the initial particle with the lowest index structure = sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, 21, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), )), def kernel(self, evaluation, parent, xs, kTs): # Retrieve the collinear variable x x = xs[0] kT = kTs[0] # Set spin correlations evaluation['spin_correlations'] = [ None, ((parent, (kT, )), ), ] # The factor 'x' that should be part of the initial_state_crossing_factor cancels # against the extra prefactor 1/x in the collinear factorization formula # (see Eq. (8) of NNLO compatible NLO scheme publication arXiv:0903.1218v2) initial_state_crossing_factor = 1. # Correct for the ratio of color-averaging factor between the real ME # initial state flavor (gluon) and the one of the reduced Born ME (gluon) initial_state_crossing_factor *= 1. z = 1. / x # We re-use here the Altarelli-Parisi Kernel of the P_g\bar{g} final state kernel # The line below implements the g_{\mu\nu} part of the splitting kernel. # Notice that the extra longitudinal terms included in the spin-correlation 'None' # from the relation: # \sum_\lambda \epsilon_\lambda^\mu \epsilon_\lambda^{\star\nu} # = g^{\mu\nu} + longitudinal terms # are irrelevant because Ward identities evaluate them to zero anyway. norm = initial_state_crossing_factor * 2. * self.CA evaluation['values'][(0, 0, 0)] = { 'finite': norm * ((z / (1. - z)) + ((1. - z) / z)) } evaluation['values'][(1, 0, 0)] = { 'finite': -norm * 2. * z * (1. - z) / kT.square() } return evaluation
class QCD_final_collinear_0_gq(QCD_final_collinear_0_XX): """g q collinear tree-level current.""" structure = sub.SingularStructure(sub.CollStructure( sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(1, +1, sub.SubtractionLeg.FINAL), )) def kernel(self, evaluation, parent, zs, kTs): # Retrieve the collinear variables z = zs[0] # Compute the kernel evaluation['values'][(0, 0, 0)] = { 'finite' : \ self.CF * (1 + (1-z)**2) / z } return evaluation
class QCD_final_collinear_0_QQxq(QCD_final_collinear_0_XX): """q Q Q~ triple-collinear tree-level current.""" structure = sub.SingularStructure(sub.CollStructure( sub.SubtractionLeg(0, +1, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(1, -1, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(2, +2, sub.SubtractionLeg.FINAL), )) def __init__(self,*args,**kwargs): # TODO THIS SHOULD NOT BE USED YET raise NotImplementedError def C123_Qqqx_kernel(self, z1, z2, z3, s12, s13, s23, s123): t123 = tijk(z1, z2, s12, s13, s23) sqrbrk = -(t123 ** 2)/(s12*s123) sqrbrk += (4*z3 + (z1-z2)**2) / (z1+z2) sqrbrk += z1 + z2 - s12/s123 return sqrbrk / (s12*s123) # def kernel(self, zs, kTs, invariants, parent, reduced_kinematics): # #raise NotImplementedError TODO DEV # # Retrieve the collinear variables # z = zs[0] # kT = kTs[0] # # Instantiate the structure of the result # evaluation = utils.SubtractionCurrentEvaluation({ # 'spin_correlations': [None, ((parent, (kT,)),), ], # 'color_correlations': [None], # 'reduced_kinematics': [reduced_kinematics], # 'values': {(0, 0, 0): {'finite': None}, # (1, 0, 0): {'finite': None}, } # }) # # Compute the kernel # # The line below implements the g_{\mu\nu} part of the splitting kernel. # # Notice that the extra longitudinal terms included in the spin-correlation 'None' # # from the relation: # # \sum_\lambda \epsilon_\lambda^\mu \epsilon_\lambda^{\star\nu} # # = g^{\mu\nu} + longitudinal terms # # are irrelevant because Ward identities evaluate them to zero anyway. # evaluation['values'][(0, 0, 0)]['finite'] = self.TR # evaluation['values'][(1, 0, 0)]['finite'] = 4 * self.TR * z * (1-z) / kT.square() # return evaluation
class QCD_final_collinear_0_gg(QCD_final_collinear_with_soft): """g g collinear tree-level current.""" structure = sub.SingularStructure( sub.CollStructure( sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), )) def kernel(self, zs, kTs, parent, reduced_kinematics): # Retrieve the collinear variables z = zs[0] kT = kTs[0] # Instantiate the structure of the result evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [ None, ((parent, (kT, )), ), ], 'color_correlations': [None], 'reduced_kinematics': [reduced_kinematics], 'values': { (0, 0, 0): { 'finite': None }, (1, 0, 0): { 'finite': None }, } }) # Compute the kernel # The line below implements the g_{\mu\nu} part of the splitting kernel. # Notice that the extra longitudinal terms included in the spin-correlation 'None' # from the relation: # \sum_\lambda \epsilon_\lambda^\mu \epsilon_\lambda^{\star\nu} # = g^{\mu\nu} + longitudinal terms # are irrelevant because Ward identities evaluate them to zero anyway. evaluation['values'][(0, 0, 0)]['finite'] = \ 0. evaluation['values'][(1, 0, 0)]['finite'] = \ -2. * self.CA * 2. * z * (1. - z) / kT.square() return evaluation
def get_final_PS_point_direct(self, PS_point, children): recoilers = tuple( i for i in PS_point.keys() if i not in (1, 2, children[0], children[1], children[2]) ) def dummy_leg(i): return subtraction.SubtractionLeg(i, 21, subtraction.SubtractionLeg.FINAL) structure = subtraction.SingularStructure( substructures=[subtraction.CollStructure( legs=(dummy_leg(children[0]), dummy_leg(children[1]), dummy_leg(children[2])) ), ], legs=(dummy_leg(r) for r in recoilers) ) leg_numbers_map = subtraction.bidict({ i: frozenset({i,}) for i in PS_point.keys() if i not in (children[0], children[1], children[2])}) leg_numbers_map[2000] = frozenset({children[0], children[1], children[2]}) mapping = mappings.FinalRescalingOneMapping final_PS_point, mapping_vars = mapping.map_to_lower_multiplicity( PS_point, structure, leg_numbers_map, compute_jacobian=True) return final_PS_point, mapping_vars
class QCD_initial_collinear_0_qqpqp(QCD_initial_collinear_0_XXX): """qg collinear ISR tree-level current. q(initial) > q(initial_after_emission) q'(final) qbar' (final) """ # Make sure to have the initial particle with the lowest index structure = [ sub.SingularStructure(sub.CollStructure( sub.SubtractionLeg(0, +1, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(2, -2, sub.SubtractionLeg.FINAL), )), ] def kernel(self, evaluation, parent, variables): # Retrieve the collinear variable x x_a, x_r, x_s = variables['xs'] kT_a, kT_r, kT_s = variables['kTs'] s_ar, s_as, s_rs = variables['ss'][(0,1)], variables['ss'][(0,2)], variables['ss'][(1,2)] # The factor 'x' that should be part of the initial_state_crossing_factor cancels # against the extra prefactor 1/x in the collinear factorization formula # (see Eq. (8) of NNLO compatible NLO scheme publication arXiv:0903.1218v2) initial_state_crossing_factor = 1. # Correct for the ratio of color-averaging factor between the real ME # initial state flavor (quark) and the one of the reduced Born ME (quark) initial_state_crossing_factor *= 1. for spin_correlation_vector, weight in AltarelliParisiKernels.P_qqpqp(self, 1./x_a, -x_r/x_a, -x_s/x_a, -s_ar, -s_as, s_rs, kT_a, kT_r, kT_s ): complete_weight = weight*initial_state_crossing_factor if spin_correlation_vector is None: evaluation['values'][(0, 0, 0)] = {'finite': complete_weight[0]} else: evaluation['spin_correlations'].append((parent, spin_correlation_vector)) evaluation['values'][(len(evaluation['spin_correlations'])-1, 0, 0)] = {'finite': complete_weight[0]} return evaluation
def __init__(self, mapping, intermediate_masses, final_masses): self.mapping = mapping assert len(intermediate_masses) == len(final_masses) self.generator = psgen.FlatInvertiblePhasespace([ 0., ] * 2, intermediate_masses, (0.5, 0.5), beam_types=(0, 0)) self.momenta_dict = sub.bidict({ 1: frozenset((1, )), 2: frozenset((2, )) }) legs = [] substructures = [] self.final_masses_m = dict() self.final_masses_s = dict() self.intermediate_masses_m = dict() self.intermediate_masses_s = dict() for i in range(len(intermediate_masses)): self.momenta_dict[i + 3] = frozenset((i + 3, )) if intermediate_masses[i] == final_masses[i]: legs.append(MappedPS.leg(i + 3)) else: substructures.append(MappedPS.structure(i + 3)) self.final_masses_m['m2' + str(i + 3)] = final_masses[i]**2 self.final_masses_s['s' + str(i + 3)] = final_masses[i]**2 self.intermediate_masses_m['m2' + str(i + 3)] = intermediate_masses[i]**2 self.intermediate_masses_s['s' + str(i + 3)] = intermediate_masses[i]**2 self.singular_structure = sub.SingularStructure( legs=legs, substructures=substructures) print self.singular_structure
class NoSoft(currents.QCDLocalCurrent): """There is no explicit soft counterterm in this scheme. It is distributed into collinear counterterms""" is_zero = True squared_orders = {'QCD': 2} n_loops = 0 structure = sub.SingularStructure( sub.SoftStructure(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL))) def evaluate_subtraction_current(self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, **opts): # Just return 0 result = utils.SubtractionCurrentResult() result.add_result(utils.SubtractionCurrentEvaluation.zero(), hel_config=hel_config, squared_orders=tuple( sorted(current.get('squared_orders').items()))) return result
class QCD_initial_softcollinear_0_Xg(currents.QCDLocalCurrent): """NLO tree-level (initial) soft-collinear currents.""" is_cut = staticmethod(colorful_pp_config.soft_cut) factor = staticmethod(colorful_pp_config.soft_factor) get_recoilers = staticmethod(colorful_pp_config.get_recoilers) squared_orders = {'QCD': 2} n_loops = 0 soft_structure = sub.SoftStructure( legs=(sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), )) soft_coll_structure_q = sub.CollStructure( substructures=(soft_structure, ), legs=(sub.SubtractionLeg(0, 1, sub.SubtractionLeg.INITIAL), )) soft_coll_structure_g = sub.CollStructure( substructures=(soft_structure, ), legs=(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.INITIAL), )) structure_q = sub.SingularStructure( substructures=(soft_coll_structure_q, )) structure_g = sub.SingularStructure( substructures=(soft_coll_structure_g, )) mapping = colorful_pp_config.initial_soft_coll_mapping divide_by_jacobian = colorful_pp_config.divide_by_jacobian variables = staticmethod(colorful_pp_config.initial_coll_variables) def __init__(self, *args, **opts): # Make sure it is initialized with the proper set of options and remove them # before calling the mother constructor if 'color_charge' not in opts: raise CurrentImplementationError( "The current '%s' must be instantiated with " % self.__class__.__name__ + "a 'color_charge' option specified.") color_charge = opts.pop('color_charge') super(QCD_initial_softcollinear_0_Xg, self).__init__(*args, **opts) # At this state color_charge is the string of the group factor ('CA' or 'CF'); # now that the mother constructor has been called, # the group factors have been initialized and we can retrieve them. self.color_charge = getattr(self, color_charge) @classmethod def does_implement_this_current(cls, current, model): if not cls.check_current_properties(current): return None leg_numbers_map = cls.structure_q.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav() + 1)]) if leg_numbers_map is not None: color_charge = 'CF' else: leg_numbers_map = cls.structure_g.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav() + 1)]) if leg_numbers_map is not None: color_charge = 'CA' if leg_numbers_map is None: return None #soft_structure = sub.SingularStructure(sub.SoftStructure( # legs=(sub.SubtractionLeg(leg_numbers_map[0], 21, sub.SubtractionLeg.FINAL),))) mapping_singular_structure = current.get( 'singular_structure').get_copy() return { 'leg_numbers_map': leg_numbers_map, 'color_charge': color_charge, 'mapping_singular_structure': mapping_singular_structure } def evaluate_subtraction_current(self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, Q=None, **opts): if higher_PS_point is None: raise CurrentImplementationError( self.name() + " needs the phase-space points before mapping.") if momenta_dict is None: raise CurrentImplementationError( self.name() + " requires a momentum routing dictionary.") if not hel_config is None: raise CurrentImplementationError( self.name() + " does not support helicity assignment.") if Q is None: raise CurrentImplementationError( self.name() + " requires the total mapping momentum Q.") # Retrieve alpha_s and mu_r model_param_dict = self.model.get('parameter_dict') alpha_s = model_param_dict['aS'] mu_r = model_param_dict['MU_R'] # Perform mapping this_mapping_singular_structure = self.mapping_singular_structure.get_copy( ) this_mapping_singular_structure.legs = self.get_recoilers( reduced_process) lower_PS_point, mapping_vars = self.mapping.map_to_lower_multiplicity( higher_PS_point, this_mapping_singular_structure, momenta_dict, compute_jacobian=self.divide_by_jacobian) reduced_kinematics = (None, lower_PS_point) # Include the counterterm only in a part of the phase space children = tuple(self.leg_numbers_map[i] for i in sorted(self.leg_numbers_map.keys())) pC_child = higher_PS_point[children[0]] pS = higher_PS_point[children[1]] parent = momenta_dict.inv[frozenset(children)] if self.is_cut(Q=Q, pC=pC_child, pS=pS): return utils.SubtractionCurrentResult.zero( current=current, hel_config=hel_config, reduced_kinematics=('IS_CUT', lower_PS_point)) pC_mother = pC_child - pS pC_tilde = lower_PS_point[parent] # Now instantiate what the result will be evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [None], 'color_correlations': [None], 'reduced_kinematics': [reduced_kinematics], 'values': { (0, 0, 0): { 'finite': None } } }) # Evaluate kernel xs, kTs = self.variables(higher_PS_point, pC_tilde, children, Q=Q) x = xs[0] # See Eq. (4.17) of NNLO compatible NLO scheme publication arXiv:0903.1218v2 # There is no need for the ratio of color-averaging factor between the real ME # initial state flavor and the one of the reduced Born ME as they are either both # gluons or both quarks evaluation['values'][(0, 0, 0)]['finite'] = self.color_charge * (2. / (1. - x)) # Add the normalization factors # Note: normalising with (pC_tilde+pS).square() will *not* work! norm = 8. * math.pi * alpha_s / (pC_child + pS).square() norm *= self.factor(Q=Q, pC=pC_mother, pS=pS) for k in evaluation['values']: evaluation['values'][k]['finite'] *= norm # Construct and return result result = utils.SubtractionCurrentResult() result.add_result(evaluation, hel_config=hel_config, squared_orders=tuple( sorted(current.get('squared_orders').items()))) return result
class QCD_C_FqFqx_C_IqpFqFqx(currents.GeneralQCDLocalCurrent): """ Nested FF (q_qx) collinear within IFF (q_q'q'x).""" squared_orders = {'QCD': 4} n_loops = 0 divide_by_jacobian = colorful_pp_config.divide_by_jacobian # We should not need global variables for this current variables = None # Now define the matching singular structures sub_coll_structure = sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(10, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -2, sub.SubtractionLeg.FINAL), ) ) # This counterterm will be used if any of the structures of the list below matches structure = [ # Match both the case of the initial state being a quark and/or antiquark sub.SingularStructure(substructures=(sub.CollStructure( substructures=(sub_coll_structure,), legs=(sub.SubtractionLeg(1, +1, sub.SubtractionLeg.INITIAL),) ),)), ] # An now the mapping rules mapping_rules = [ { 'singular_structure' : sub.SingularStructure(substructures=(sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(10, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -2, sub.SubtractionLeg.FINAL), ) ),)), 'mapping' : colorful_pp_config.final_coll_mapping, # Intermediate legs should be strictly superior to a 1000 'momenta_dict' : bidict({1001:frozenset((10,11))}), 'variables' : currents.CompoundVariables(kernel_variables.colorful_pp_FFn_variables), 'is_cut' : colorful_pp_config.generalised_cuts, 'reduced_recoilers' : colorful_pp_config.get_initial_state_recoilers, 'additional_recoilers' : sub.SubtractionLegSet([sub.SubtractionLeg(1, +1, sub.SubtractionLeg.INITIAL)]), }, { 'singular_structure': sub.SingularStructure(substructures=(sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(1, +1, sub.SubtractionLeg.INITIAL), sub.SubtractionLeg(1001, 21, sub.SubtractionLeg.FINAL), ) ),)), 'mapping' : colorful_pp_config.initial_coll_mapping, # -1 indicates that this ID should be replaced by the first overall parent connecting to the ME 'momenta_dict' : bidict({-1: frozenset((1001, 1))}), 'variables' : currents.CompoundVariables(kernel_variables.colorful_pp_IFn_variables), 'is_cut' : colorful_pp_config.generalised_cuts, 'reduced_recoilers' : colorful_pp_config.get_final_state_recoilers, 'additional_recoilers' : sub.SubtractionLegSet([]), }, ] def kernel(self, evaluation, all_steps_info, global_variables): """ Evaluate this I(FF) counterterm given the supplied variables. """ kT_FF = all_steps_info[0]['variables'][0]['kTs'][(0,(1,))] z_FF = all_steps_info[0]['variables'][0]['zs'][0] s_rs = all_steps_info[0]['variables'][0]['ss'][(0,1)] kT_IF = all_steps_info[1]['variables'][0]['kTs'][0] x_IF = all_steps_info[1]['variables'][0]['xs'][0] s_a_rs = all_steps_info[1]['variables'][0]['ss'][(0,1)] p_a_hat = all_steps_info[1]['higher_PS_point'][ all_steps_info[1]['bundles_info'][0]['initial_state_children'][0] ] p_rs_hat = all_steps_info[1]['higher_PS_point'][ all_steps_info[1]['bundles_info'][0]['final_state_children'][0] ] parent = all_steps_info[1]['bundles_info'][0]['parent'] #misc.sprint(s_rs, s_a_rs) #misc.sprint(z_FF, x_IF) #misc.sprint(kT_FF, kT_IF) #misc.sprint(p_a_hat, parent) # We must include here propagator factors, but no correction for symmetry # or averaging factor is necessary in this particular pure-quark kernel initial_state_crossing = -1.0 prefactor = initial_state_crossing*(1./(s_rs*s_a_rs)) for spin_correlation_vector, weight in AltarelliParisiKernels.P_q_qpqp(self, z_FF, 1./x_IF, kT_FF, -p_a_hat, p_rs_hat): complete_weight = weight * prefactor if spin_correlation_vector is None: evaluation['values'][(0, 0, 0)] = {'finite': complete_weight[0]} else: evaluation['spin_correlations'].append((parent, spin_correlation_vector)) evaluation['values'][(len(evaluation['spin_correlations']) - 1, 0, 0)] = {'finite': complete_weight[0]} return evaluation
class QCD_initial_soft_collinear_0_qqpqp(QCD_initial_soft_collinear_0_kX): """q' qbar' soft collinear ISR tree-level current. q(initial) > q(initial_after_emission) Soft(q'(final) qbar' (final)) """ soft_structure = sub.SoftStructure( legs=( sub.SubtractionLeg(10, +1, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -1, sub.SubtractionLeg.FINAL), ) ) soft_coll_structure_q = sub.CollStructure( substructures=(soft_structure, ), legs=(sub.SubtractionLeg(0, 1, sub.SubtractionLeg.INITIAL), ) ) soft_coll_structure_g = sub.CollStructure( substructures=(soft_structure, ), legs=(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.INITIAL), ) ) structure_q = sub.SingularStructure(substructures=(soft_coll_structure_q, )) structure_g = sub.SingularStructure(substructures=(soft_coll_structure_g, )) structure = [structure_q, structure_g] expected_init_opts = tuple(list(QCD_initial_soft_collinear_0_kX.expected_init_opts)+['color_charge',]) def __init__(self, *args, **opts): """ Specialise constructor so as to assign value to the specified color charge. """ super(QCD_initial_soft_collinear_0_qqpqp, self).__init__(*args, **opts) # Turn 'CA' into the actual numerical value self.CA for instance self.color_charge = getattr(self, self.color_charge) @classmethod def does_implement_this_current(cls, current, model): """ Overwrite this function so as to be able to specify the color-factor to consider.""" res = super(QCD_initial_soft_collinear_0_qqpqp, cls).does_implement_this_current(current, model) if res is None: return None color_charge = 'CF' leg_numbers_map = cls.structure_q.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav()+1)]) if leg_numbers_map is None: color_charge = 'CA' leg_numbers_map = cls.structure_g.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav()+1)]) if leg_numbers_map is None: return None res['color_charge'] = color_charge return res def kernel(self, evaluation, parent, variables): # Retrieve the collinear variable x x_a, x_r, x_s = variables['xs'] kT_a, kT_r, kT_s = variables['kTs'] s_ar, s_as, s_rs = variables['ss'][(0,1)], variables['ss'][(0,2)], variables['ss'][(1,2)] s_a_rs = s_ar + s_as kernel = 2. * ( 1. / (x_r + x_s) - (((s_ar * x_s - s_as * x_r) ** 2) / (s_a_rs * s_rs * ((x_r + x_s) ** 2))) ) evaluation['values'][(0, 0, 0)] = {'finite': self.color_charge * self.TR * kernel } return evaluation
class NoSoftCollinear(currents.QCDLocalCurrent): """There is no explicit soft counterterm in this scheme. It is distributed into collinear counterterms""" is_zero = True squared_orders = {'QCD': 2} n_loops = 0 soft_structure = sub.SoftStructure( legs=(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL), )) soft_coll_structure_q = sub.CollStructure(substructures=(soft_structure, ), legs=(sub.SubtractionLeg( 1, 1, sub.SubtractionLeg.FINAL), )) soft_coll_structure_g = sub.CollStructure(substructures=(soft_structure, ), legs=(sub.SubtractionLeg( 1, 21, sub.SubtractionLeg.FINAL), )) structure_q = sub.SingularStructure( substructures=(soft_coll_structure_q, )) structure_g = sub.SingularStructure( substructures=(soft_coll_structure_g, )) @classmethod def does_implement_this_current(cls, current, model): if not cls.check_current_properties(current): return None color_charge = 'CF' leg_numbers_map = cls.structure_q.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav() + 1)]) if leg_numbers_map is None: color_charge = 'CA' leg_numbers_map = cls.structure_g.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav() + 1)]) if leg_numbers_map is None: return None mapping_singular_structure = current.get( 'singular_structure').get_copy() return { 'leg_numbers_map': leg_numbers_map, 'color_charge': color_charge, 'mapping_singular_structure': mapping_singular_structure } def __init__(self, *args, **opts): for opt_name in [ 'color_charge', ]: try: setattr(self, opt_name, opts.pop(opt_name)) except KeyError: raise CurrentImplementationError("__init__ of " + self.__class__.__name__ + " requires " + opt_name) super(NoSoftCollinear, self).__init__(*args, **opts) # At this state color_charge is the string of the group factor ('CA' or 'CF'); # now that the super constructor has been called, # the group factors have been initialized and we can retrieve them. self.color_charge = getattr(self, self.color_charge) def evaluate_subtraction_current(self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, **opts): # Just return 0 result = utils.SubtractionCurrentResult() result.add_result(utils.SubtractionCurrentEvaluation.zero(), hel_config=hel_config, squared_orders=tuple( sorted(current.get('squared_orders').items()))) return result
class QCD_final_softcollinear_0_gX(currents.QCDLocalCurrent): """NLO tree-level (final) soft-collinear currents. The momenta used in this current are the mapped momenta from the soft mapping.""" is_cut = staticmethod(colorful_pp_config.soft_cut) factor = staticmethod(colorful_pp_config.soft_factor) get_recoilers = staticmethod(colorful_pp_config.get_recoilers) variables = staticmethod(colorful_pp_config.final_soft_coll_variables) squared_orders = {'QCD': 2} n_loops = 0 soft_structure = sub.SoftStructure( legs=(sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), )) soft_coll_structure_q = sub.CollStructure(substructures=(soft_structure, ), legs=(sub.SubtractionLeg( 0, 1, sub.SubtractionLeg.FINAL), )) soft_coll_structure_g = sub.CollStructure(substructures=(soft_structure, ), legs=(sub.SubtractionLeg( 0, 21, sub.SubtractionLeg.FINAL), )) structure_q = sub.SingularStructure( substructures=(soft_coll_structure_q, )) structure_g = sub.SingularStructure( substructures=(soft_coll_structure_g, )) mapping = colorful_pp_config.final_soft_coll_mapping divide_by_jacobian = colorful_pp_config.divide_by_jacobian def __init__(self, *args, **opts): # Make sure it is initialized with the proper set of options and remove them # before calling the mother constructor if 'color_charge' not in opts: raise CurrentImplementationError( "The current '%s' must be instantiated with " % self.__class__.__name__ + "a 'color_charge' option specified.") color_charge = opts.pop('color_charge') super(QCD_final_softcollinear_0_gX, self).__init__(*args, **opts) # At this state color_charge is the string of the group factor ('CA' or 'CF'); # now that the mother constructor has been called, # the group factors have been initialized and we can retrieve them. self.color_charge = getattr(self, color_charge) @classmethod def does_implement_this_current(cls, current, model): if not cls.check_current_properties(current): return None leg_numbers_map = cls.structure_q.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav() + 1)]) if leg_numbers_map is not None: color_charge = 'CF' else: leg_numbers_map = cls.structure_g.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav() + 1)]) if leg_numbers_map is not None: color_charge = 'CA' if leg_numbers_map is None: return None #mapping_singular_structure = sub.SingularStructure(sub.SoftStructure( # legs=(sub.SubtractionLeg(leg_numbers_map[0], 21, sub.SubtractionLeg.FINAL),))) mapping_singular_structure = current.get( 'singular_structure').get_copy() return { 'leg_numbers_map': leg_numbers_map, 'color_charge': color_charge, 'mapping_singular_structure': mapping_singular_structure } def evaluate_subtraction_current(self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, Q=None, **opts): if higher_PS_point is None: raise CurrentImplementationError( self.name() + " needs the phase-space points before mapping.") if momenta_dict is None: raise CurrentImplementationError( self.name() + " requires a momentum routing dictionary.") if not hel_config is None: raise CurrentImplementationError( self.name() + " does not support helicity assignment.") if Q is None: raise CurrentImplementationError( self.name() + " requires the total mapping momentum Q.") # Retrieve alpha_s and mu_r model_param_dict = self.model.get('parameter_dict') alpha_s = model_param_dict['aS'] mu_r = model_param_dict['MU_R'] children = tuple(self.leg_numbers_map[i] for i in sorted(self.leg_numbers_map.keys())) parent = momenta_dict.inv[frozenset(children)] # Perform mapping this_mapping_singular_structure = self.mapping_singular_structure.get_copy( ) this_mapping_singular_structure.legs = self.get_recoilers( reduced_process, excluded=(parent, )) lower_PS_point, mapping_vars = self.mapping.map_to_lower_multiplicity( higher_PS_point, this_mapping_singular_structure, momenta_dict, compute_jacobian=self.divide_by_jacobian) reduced_kinematics = (None, lower_PS_point) # Include the counterterm only in a part of the phase space # children are the the set of particles that are going unresolved. # Here we have C and S going collinear with S soft. # The parent is the mapped C with a soft mapping, usually refered to as Ctilde. # S is just removed in a soft mapping. # Here S is a single particle but we obtain it as a list soft_children\ # to illustrate how multiple softs would be obtained pCtilde = lower_PS_point[parent] soft_children = [ self.leg_numbers_map[1], ] pS = sum(higher_PS_point[child] for child in soft_children) if self.is_cut(Q=Q, pC=pCtilde, pS=pS): return utils.SubtractionCurrentResult.zero( current=current, hel_config=hel_config, reduced_kinematics=('IS_CUT', lower_PS_point)) # Now instantiate what the result will be evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [None], 'color_correlations': [None], 'reduced_kinematics': [ reduced_kinematics, ], 'values': { (0, 0, 0): { 'finite': None } } }) # Evaluate kernel zs = self.variables([pS, pCtilde], Q) z = zs[0] evaluation['values'][( 0, 0, 0)]['finite'] = self.color_charge * 2. * (1. - z) / z # Add the normalization factors s12 = (pCtilde + pS).square() norm = 8. * math.pi * alpha_s / s12 norm *= self.factor(Q=Q, pC=pCtilde, pS=pS) for k in evaluation['values']: evaluation['values'][k]['finite'] *= norm # Construct and return result result = utils.SubtractionCurrentResult() result.add_result(evaluation, hel_config=hel_config, squared_orders=tuple( sorted(current.get('squared_orders').items()))) return result
class QCD_final_softcollinear_0_gX(currents.QCDLocalCurrent): """NLO tree-level (final) soft-collinear currents.""" squared_orders = {'QCD': 2} n_loops = 0 soft_structure = sub.SoftStructure( legs=(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL), ) ) soft_coll_structure_q = sub.CollStructure( substructures=(soft_structure, ), legs=(sub.SubtractionLeg(1, 1, sub.SubtractionLeg.FINAL), ) ) soft_coll_structure_g = sub.CollStructure( substructures=(soft_structure, ), legs=(sub.SubtractionLeg(1, 21, sub.SubtractionLeg.FINAL), ) ) structure_q = sub.SingularStructure(substructures=(soft_coll_structure_q, )) structure_g = sub.SingularStructure(substructures=(soft_coll_structure_g, )) is_cut = staticmethod(is_cut_soft) factor = staticmethod(factor_soft) mapping = soft_coll_mapping variables = staticmethod(variables) divide_by_jacobian = divide_by_jacobian get_recoilers = staticmethod(get_recoilers) @classmethod def does_implement_this_current(cls, current, model): if not cls.check_current_properties(current): return None color_charge = 'CF' leg_numbers_map = cls.structure_q.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav()+1)]) if leg_numbers_map is None: color_charge = 'CA' leg_numbers_map = cls.structure_g.map_leg_numbers( current.get('singular_structure'), [range(1, model.get_nflav()+1)]) if leg_numbers_map is None: return None mapping_singular_structure = current.get('singular_structure').get_copy() return { 'leg_numbers_map': leg_numbers_map, 'color_charge': color_charge, 'mapping_singular_structure': mapping_singular_structure } def __init__(self, *args, **opts): for opt_name in ['color_charge', ]: try: setattr(self, opt_name, opts.pop(opt_name)) except KeyError: raise CurrentImplementationError( "__init__ of " + self.__class__.__name__ + " requires " + opt_name) super(QCD_final_softcollinear_0_gX, self).__init__(*args, **opts) # At this state color_charge is the string of the group factor ('CA' or 'CF'); # now that the super constructor has been called, # the group factors have been initialized and we can retrieve them. self.color_charge = getattr(self, self.color_charge) def evaluate_subtraction_current( self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, **opts ): if higher_PS_point is None: raise CurrentImplementationError( self.name() + " needs the higher phase-space point." ) if momenta_dict is None: raise CurrentImplementationError( self.name() + " requires a momenta dictionary." ) if reduced_process is None: raise CurrentImplementationError( self.name() + " requires a reduced_process.") if not hel_config is None: raise CurrentImplementationError( self.name() + " does not support helicity assignment." ) # Retrieve alpha_s and mu_r model_param_dict = self.model.get('parameter_dict') alpha_s = model_param_dict['aS'] mu_r = model_param_dict['MU_R'] # Retrieve leg numbers soft_leg_number = self.leg_numbers_map[0] coll_leg_number = self.leg_numbers_map[1] children = (soft_leg_number, coll_leg_number, ) parent = momenta_dict.inv[frozenset(children)] # Perform mapping self.mapping_singular_structure.legs = self.get_recoilers( reduced_process, excluded=(parent, )) lower_PS_point, mapping_vars = self.mapping.map_to_lower_multiplicity( higher_PS_point, self.mapping_singular_structure, momenta_dict, compute_jacobian=self.divide_by_jacobian ) # Retrieve kinematics Q = mapping_vars['Q'] pS = higher_PS_point[soft_leg_number] pC = pS + higher_PS_point[coll_leg_number] jacobian = mapping_vars.get('jacobian', 1) # Include the counterterm only in a part of the phase space if self.is_cut(Q=Q, pS=pS): return utils.SubtractionCurrentResult.zero( current=current, hel_config=hel_config, reduced_kinematics=(None, lower_PS_point)) # Evaluate kernel zs, kTs = self.variables(higher_PS_point, lower_PS_point[parent], children, Q=Q) z = zs[0] evaluation = utils.SubtractionCurrentEvaluation.zero( reduced_kinematics=(None, lower_PS_point)) evaluation['values'][(0, 0, 0)]['finite'] = self.color_charge * 2 * (1-z) / z # Add the normalization factors s12 = pC.square() norm = 8 * math.pi * alpha_s / s12 norm *= self.factor(Q=Q, pC=pC, pS=pS) norm /= jacobian for k in evaluation['values']: evaluation['values'][k]['finite'] *= norm # Construct and return result result = utils.SubtractionCurrentResult() result.add_result( evaluation, hel_config=hel_config, squared_orders=tuple(sorted(current.get('squared_orders').items()))) return result
class QCD_soft_0_g(currents.QCDLocalCurrent): """Soft gluon eikonal current at tree level, eq.4.12-4.13 of arXiv:0903.1218.""" squared_orders = {'QCD': 2} n_loops = 0 structure = sub.SingularStructure( sub.SoftStructure(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL)) ) is_cut = staticmethod(is_cut_soft) factor = staticmethod(factor_soft) mapping = soft_mapping divide_by_jacobian = divide_by_jacobian get_recoilers = staticmethod(get_recoilers) @staticmethod def eikonal(pi, pj, ps): """Eikonal factor for soft particle with momentum ps emitted from the dipole with momenta pi and pj. """ pipj = pi.dot(pj) pips = pi.dot(ps) pjps = pj.dot(ps) return pipj/(pips*pjps) def evaluate_subtraction_current( self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, **opts ): if higher_PS_point is None: raise CurrentImplementationError( self.name() + " needs the higher phase-space point." ) if momenta_dict is None: raise CurrentImplementationError( self.name() + " requires a momenta dictionary." ) if reduced_process is None: raise CurrentImplementationError( self.name() + " requires a reduced_process.") if not hel_config is None: raise CurrentImplementationError( self.name() + " does not support helicity assignment." ) # Retrieve alpha_s and mu_r model_param_dict = self.model.get('parameter_dict') alpha_s = model_param_dict['aS'] mu_r = model_param_dict['MU_R'] # Retrieve leg numbers soft_leg_number = self.leg_numbers_map[0] # Perform mapping self.mapping_singular_structure.legs = self.get_recoilers(reduced_process) lower_PS_point, mapping_vars = soft_mapping.map_to_lower_multiplicity( higher_PS_point, self.mapping_singular_structure, momenta_dict, compute_jacobian=self.divide_by_jacobian ) # Retrieve kinematics Q = mapping_vars['Q'] pS = higher_PS_point[soft_leg_number] jacobian = mapping_vars.get('jacobian', 1) # Include the counterterm only in a part of the phase space if self.is_cut(Q=Q, pS=pS): return utils.SubtractionCurrentResult.zero( current=current, hel_config=hel_config, reduced_kinematics=(None, lower_PS_point)) # Normalization factors norm = -4 * math.pi * alpha_s norm *= self.factor(Q=Q, pS=pS) norm /= jacobian # Find all colored leg numbers in the reduced process all_colored_parton_numbers = [] for leg in reduced_process.get('legs'): if self.model.get_particle(leg.get('id')).get('color') == 1: continue all_colored_parton_numbers.append(leg.get('number')) # Initialize the result evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [None], 'color_correlations': [], 'reduced_kinematics': [(None, lower_PS_point)], 'values': {} }) # Loop over colored parton number pairs (a, b) # and add the corresponding contributions to this current color_correlation_index = 0 for i, a in enumerate(all_colored_parton_numbers): # Use the symmetry of the color correlation and soft current (a,b) <-> (b,a) for b in all_colored_parton_numbers[i:]: # Write the eikonal for that pair if a != b: mult_factor = 2. else: mult_factor = 1. pa = higher_PS_point[a] pb = higher_PS_point[b] eikonal = self.eikonal(pa, pb, pS) evaluation['color_correlations'].append( ((a, b), ) ) evaluation['values'][(0, color_correlation_index, 0)] = { 'finite': norm * mult_factor * eikonal } color_correlation_index += 1 result = utils.SubtractionCurrentResult() result.add_result( evaluation, hel_config=hel_config, squared_orders=tuple(sorted(current.get('squared_orders').items())) ) return result
class QCD_S_FqFqx_C_FqFqx(currents.GeneralQCDLocalCurrent): """ Nested soft FF (q_qx) limit within collinear FF (q_qx) limit.""" squared_orders = {'QCD': 4} n_loops = 0 divide_by_jacobian = colorful_pp_config.divide_by_jacobian # We should not need global variables for this current variables = None # Now define the matching singular structures sub_coll_structure = sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(10, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -2, sub.SubtractionLeg.FINAL), ) ) # This counterterm will be used if any of the structures of the list below matches structure = [ # Match both the case of the initial state being a quark and/or antiquark sub.SingularStructure(substructures=(sub.SoftStructure( substructures=(sub_coll_structure,), legs=tuple([]) ),)), ] # An now the mapping rules mapping_rules = [ { 'singular_structure' : sub.SingularStructure(substructures=(sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(10, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -2, sub.SubtractionLeg.FINAL), ) ),)), 'mapping' : colorful_pp_config.final_coll_mapping, # Intermediate legs should be strictly superior to a 1000 'momenta_dict' : bidict({1001:frozenset((10,11))}), 'variables' : currents.CompoundVariables(kernel_variables.colorful_pp_FFn_variables), 'is_cut' : colorful_pp_config.generalised_cuts, 'reduced_recoilers' : colorful_pp_config.get_initial_state_recoilers, 'additional_recoilers' : sub.SubtractionLegSet([]), }, { 'singular_structure': sub.SingularStructure(substructures=(sub.SoftStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(1001, 21, sub.SubtractionLeg.FINAL), ) ),)), 'mapping' : colorful_pp_config.soft_mapping, # -1 indicates that this ID should be replaced by the first overall parent connecting to the ME 'momenta_dict' : bidict({}), 'variables' : None, 'is_cut' : colorful_pp_config.generalised_cuts, 'reduced_recoilers' : colorful_pp_config.get_final_state_recoilers, 'additional_recoilers' : sub.SubtractionLegSet([]), }, ] def kernel(self, evaluation, all_steps_info, global_variables): """ Evaluate this I(FF) counterterm given the supplied variables. """ kT_FF = all_steps_info[0]['variables'][0]['kTs'][(0,(1,))] z_FF = all_steps_info[0]['variables'][0]['zs'][0] s_rs = all_steps_info[0]['variables'][0]['ss'][(0,1)] parent = all_steps_info[0]['bundles_info'][0]['parent'] prefactor = 1./s_rs for spin_correlation_vector, weight in AltarelliParisiKernels.P_qq(self, z_FF, kT_FF): complete_weight = weight * prefactor if spin_correlation_vector is None: evaluation['values'][(0, 0, 0)] = {'finite': complete_weight[0]} else: evaluation['spin_correlations'].append( ( (parent, (spin_correlation_vector,) ), ) ) evaluation['values'][(len(evaluation['spin_correlations']) - 1, 0, 0)] = {'finite': complete_weight[0]} return evaluation def soft_kernel(self, evaluation, colored_partons, all_steps_info, global_variables): """Evaluate a collinear type of splitting kernel, which *does* need to know about the reduced process Should be specialised by the daughter class if not dummy """ new_evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations' : [ None, ], 'color_correlations': [ ], 'reduced_kinematics': evaluation['reduced_kinematics'], 'values': { } }) overall_lower_PS_point = all_steps_info[-1]['lower_PS_point'] soft_leg_number = all_steps_info[-1]['bundles_info'][0]['final_state_children'][0] pr = all_steps_info[-1]['higher_PS_point'][soft_leg_number] colored_parton_numbers = sorted(colored_partons.keys()) for i, a in enumerate(colored_parton_numbers): for b in colored_parton_numbers[i:]: # Write the eikonal for that pair if a!=b: mult_factor = 1. else: mult_factor = 1./2. pi = overall_lower_PS_point[a] pk = overall_lower_PS_point[b] composite_weight = EpsilonExpansion({'finite': 0.}) for (sc, cc, rk), coll_weight in evaluation['values'].items(): if evaluation['spin_correlations'][sc] is None: # We *subtract* here the contribution because the non-spin-correlated contributin is -g^{\mu\nu} composite_weight -= SoftKernels.eikonal_g(self, pi, pk, pr, spin_corr_vector=None)*EpsilonExpansion(coll_weight) else: # Normally the collinear current should have built spin-correlations with the leg number corresponding # to the soft one in the context of this soft current assert len(evaluation['spin_correlations'][sc])==1 parent_number, spin_corr_vecs = evaluation['spin_correlations'][sc][0] assert soft_leg_number==parent_number assert len(spin_corr_vecs)==1 spin_corr_vec = spin_corr_vecs[0] composite_weight += SoftKernels.eikonal_g(self, pi, pk, pr, spin_corr_vector=spin_corr_vec)*EpsilonExpansion(coll_weight) new_evaluation['color_correlations'].append( ((a, b), ) ) new_evaluation['values'][(0,len(new_evaluation['color_correlations'])-1,0)] = composite_weight*mult_factor return new_evaluation
class QCD_S_FqFqx_C_FqFqx_C_IqpFqFqx(currents.GeneralQCDLocalCurrent): """ Nested soft FF (q_qx) limit within collinear FF (q_qx) limit with collinear limit IFF (q' q_qx).""" squared_orders = {'QCD': 4} n_loops = 0 divide_by_jacobian = colorful_pp_config.divide_by_jacobian # In order to build the IF variables using the initial parent momentum which is absent from any mapping # structure, we use the global variables variables = staticmethod(QCD_S_FqFqx_C_FqFqx_C_IqpFqFqx_global_IFF_softFF_variables) # Now define the matching singular structures sub_coll_structure = sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(10, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -2, sub.SubtractionLeg.FINAL), ) ) soft_structure = sub.SoftStructure( substructures=(sub_coll_structure,), legs=tuple([]) ) # This counterterm will be used if any of the structures of the list below matches structure = [ # Match the case of the initial state being a quark and/or antiquark sub.SingularStructure(substructures=(sub.CollStructure( substructures=(soft_structure,), legs=(sub.SubtractionLeg(1, +1, sub.SubtractionLeg.INITIAL),) ),)), ] # An now the mapping rules mapping_rules = [ { 'singular_structure' : sub.SingularStructure(substructures=(sub.CollStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(10, +2, sub.SubtractionLeg.FINAL), sub.SubtractionLeg(11, -2, sub.SubtractionLeg.FINAL), ) ),)), 'mapping' : colorful_pp_config.final_coll_mapping, # Intermediate legs should be strictly superior to a 1000 'momenta_dict' : bidict({1001:frozenset((10,11))}), 'variables' : currents.CompoundVariables(kernel_variables.colorful_pp_FFn_variables), 'is_cut' : colorful_pp_config.generalised_cuts, 'reduced_recoilers' : colorful_pp_config.get_initial_state_recoilers, 'additional_recoilers' : sub.SubtractionLegSet([sub.SubtractionLeg(1, +1, sub.SubtractionLeg.INITIAL),]), }, { 'singular_structure': sub.SingularStructure(substructures=(sub.SoftStructure( substructures=tuple([]), legs=( sub.SubtractionLeg(1001, 21, sub.SubtractionLeg.FINAL), ) ),)), 'mapping' : colorful_pp_config.soft_mapping, # -1 indicates that this ID should be replaced by the first overall parent connecting to the ME # The momenta dictionary below is irrelevant for the soft_mapping used above will make sure that # it applies the necessary relabelling of the final-state leg 33 to the parent -1 which will be # used by the reduced ME called with it. 'momenta_dict' : bidict({-1: frozenset((1,))}), 'variables' : None, 'is_cut' : colorful_pp_config.generalised_cuts, 'reduced_recoilers' : colorful_pp_config.get_final_state_recoilers, 'additional_recoilers' : sub.SubtractionLegSet([]), }, ] def kernel(self, evaluation, all_steps_info, global_variables): """ Evaluate this I(FF) counterterm given the supplied variables. """ kT_FF = all_steps_info[0]['variables'][0]['kTs'][(0,(1,))] z_FF = all_steps_info[0]['variables'][0]['zs'][0] s_rs = all_steps_info[0]['variables'][0]['ss'][(0,1)] kT_IF = global_variables['kTs'][0] x_IF = global_variables['xs'][0] s_a_rs = global_variables['ss'][(0,1)] p_a_tilde = global_variables['p_a_tilde'] p_rs_hat = all_steps_info[0]['lower_PS_point'][ all_steps_info[0]['bundles_info'][0]['parent'] ] # misc.sprint(s_rs,s_a_rs) # misc.sprint(p_a_tilde,p_rs_hat,p_a_tilde.dot(p_rs_hat)) # misc.sprint(p_a_tilde,kT_FF,p_a_tilde.dot(kT_FF)) # misc.sprint(kT_FF, kT_FF.square()) # misc.sprint(x_IF) # misc.sprint(z_FF,(1.-z_FF)) evaluation['values'][(0,0,0)] = EpsilonExpansion({'finite': (2./(s_rs*s_a_rs))*self.TR*self.CF*( 1./(1.-x_IF) + z_FF * (1. - z_FF) * ((2.*p_a_tilde.dot(kT_FF))**2)/(kT_FF.square()*(2.*p_a_tilde.dot(p_rs_hat))) ) }) return evaluation
class QCD_soft_0_g(currents.QCDLocalCurrent): """Soft gluon eikonal current at tree level, eq.4.12-4.13 of arXiv:0903.1218. This is modified with respect to the above reference because we replace all the two legs of the dipole of each eikonal by their mapped version. """ is_cut = staticmethod(colorful_pp_config.soft_cut) factor = staticmethod(colorful_pp_config.soft_factor) get_recoilers = staticmethod(colorful_pp_config.get_recoilers) squared_orders = {'QCD': 2} n_loops = 0 structure = sub.SingularStructure( sub.SoftStructure(sub.SubtractionLeg(0, 21, sub.SubtractionLeg.FINAL))) mapping = colorful_pp_config.soft_mapping divide_by_jacobian = colorful_pp_config.divide_by_jacobian @staticmethod def eikonal(pi, pj, ps): """Eikonal factor for soft particle with momentum ps emitted from the dipole with momenta pi and pj. """ pipj = pi.dot(pj) pips = pi.dot(ps) pjps = pj.dot(ps) return pipj / (pips * pjps) def evaluate_subtraction_current(self, current, higher_PS_point=None, momenta_dict=None, reduced_process=None, hel_config=None, Q=None, **opts): if higher_PS_point is None: raise CurrentImplementationError( self.name() + " needs the phase-space points before and after mapping.") if momenta_dict is None: raise CurrentImplementationError( self.name() + " requires a momentum routing dictionary.") if reduced_process is None: raise CurrentImplementationError(self.name() + " requires a reduced_process.") if not hel_config is None: raise CurrentImplementationError( self.name() + " does not support helicity assignment.") if Q is None: raise CurrentImplementationError( self.name() + " requires the total mapping momentum Q.") """Important note about the IF CS: - in this scheme we want to use "tilded" momenta for the dipole legs in eikonals. This is explicitly implemented in the soft local current - this implies that the correct form for the local C(ir)S(r) taken as the collinear limit of the eikonals is 1/ (p_r + p_i_tilde)^2 (1-z_r)/z_r where z_r = p_r.Q/(p_r+p_i_tilde).Q - Specializing to the case where the collinear partner of the soft particle is an initial state particle (i = a ), we have p_a_tilde = xi p_a and 2p_a.Q = Q^2 so that the soft-collinear takes the form 1/(p_r+xi p_a)^2 * xi/y_rQ where y_rQ is the usual Hungarian variable this simplifies to 1/(p_r+p_a)^2 * 1/y_rQ which is exactly the soft collinear as computed *without* tilded variables (i.e. exactly eq.5.29 of 0903.1218) As a result we use exactly the same way of evaluating the counterterms as in honest-to-god colorful. """ # Retrieve alpha_s and mu_r model_param_dict = self.model.get('parameter_dict') alpha_s = model_param_dict['aS'] mu_r = model_param_dict['MU_R'] # Now find all colored leg numbers in the reduced process all_colored_parton_numbers = [] for leg in reduced_process.get('legs'): if self.model.get_particle(leg.get('id')).get('color') == 1: continue all_colored_parton_numbers.append(leg.get('number')) soft_leg_number = self.leg_numbers_map[0] pS = higher_PS_point[soft_leg_number] # Perform mapping this_mapping_singular_structure = self.mapping_singular_structure.get_copy( ) this_mapping_singular_structure.legs = self.get_recoilers( reduced_process) lower_PS_point, mapping_vars = self.mapping.map_to_lower_multiplicity( higher_PS_point, this_mapping_singular_structure, momenta_dict, compute_jacobian=self.divide_by_jacobian) reduced_kinematics = (None, lower_PS_point) # Include the counterterm only in a part of the phase space if self.is_cut(Q=Q, pS=pS): return utils.SubtractionCurrentResult.zero( current=current, hel_config=hel_config, reduced_kinematics=('IS_CUT', lower_PS_point)) # Retrieve kinematics pS = higher_PS_point[soft_leg_number] jacobian = mapping_vars.get('jacobian', 1.) # Now instantiate what the result will be evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [None], 'color_correlations': [], 'reduced_kinematics': [ reduced_kinematics, ], 'values': {} }) # Normalization factors norm = -4. * math.pi * alpha_s norm *= self.factor(Q=Q, pS=pS) if self.divide_by_jacobian: norm /= jacobian color_correlation_index = 0 # Now loop over the colored parton number pairs (a,b) # and add the corresponding contributions to this current for i, a in enumerate(all_colored_parton_numbers): # Use the symmetry of the color correlation and soft current (a,b) <-> (b,a) for b in all_colored_parton_numbers[i:]: # Write the eikonal for that pair if a != b: mult_factor = 2. else: mult_factor = 1. #pa = sum(higher_PS_point[child] for child in momenta_dict[a]) #pb = sum(higher_PS_point[child] for child in momenta_dict[b]) pa = lower_PS_point[a] pb = lower_PS_point[b] eikonal = self.eikonal(pa, pb, pS) evaluation['color_correlations'].append(((a, b), )) evaluation['values'][(0, color_correlation_index, 0)] = { 'finite': norm * mult_factor * eikonal } color_correlation_index += 1 result = utils.SubtractionCurrentResult() result.add_result(evaluation, hel_config=hel_config, squared_orders=tuple( sorted(current.get('squared_orders').items()))) return result