def get_all_final_recoilers(reduced_process, excluded=()): model = reduced_process.get('model') return sub.SubtractionLegSet([ leg for leg in reduced_process.get('legs') if all([leg['state'] == leg.FINAL, leg['number'] not in excluded]) ])
def get_recoilers(reduced_process, excluded=()): model = reduced_process.get('model') return sub.SubtractionLegSet([ leg for leg in reduced_process.get('legs') if all([ model.get_particle(leg['id']).get('mass').upper() == 'ZERO', leg['state'] == leg.FINAL, leg['number'] not in excluded ]) ])
def map_leg_numbers_in_singular_structure(self, singular_structure, parents): """ Recursively walk through the singular structure and map the generic subtraction leg numbers to either: - the explicit indices of the resovled process - the explicit indices of the unresolved process - dummy intermediate indices """ new_subtraction_legs = [] for leg in singular_structure.legs: new_subtraction_legs.append( sub.SubtractionLeg(self.map_leg_number(leg.n, parents), leg.pdg, leg.state)) singular_structure.legs = sub.SubtractionLegSet(new_subtraction_legs) for ss in singular_structure.substructures: self.map_leg_numbers_in_singular_structure(ss, parents)
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_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_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
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 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.") if Q is None: raise CurrentImplementationError( self.name() + " requires specification of the total incoming 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'] # Retrieve leg numbers overall_children = [ ] # the legs becoming unresolved in the resolved process (momenta in the real-emission ME) overall_parents = [ ] # the parent legs in the top-level reduced process (momenta in the mapped ME of this CT) # We take one defining structure (self.structure[0]). Its top-level substructures are the independent bundles # eg (C(1,2),C(4,5),S(6)). # Using structure[0] as the defining structure is fine for the purpose below since they should # all use the same leg numbers for bundle in self.structure[0].substructures: overall_children.append( tuple(self.leg_numbers_map[l.n] for l in bundle.get_all_legs())) if self.has_parent(bundle, len(overall_children[-1])): overall_parents.append( self.get_parent(frozenset(overall_children[-1]), momenta_dict)) else: overall_parents.append(None) all_steps = [ { 'higher_PS_point': higher_PS_point }, ] overall_jacobian = 1. for i_step, mapping_information in enumerate(self.mapping_rules): # Now obtain recoilers reduced_recoilers = mapping_information['reduced_recoilers']( reduced_process, excluded=tuple(overall_parents)) additional_recoilers = sub.SubtractionLegSet( SubtractionLeg(self.map_leg_number(l.n, overall_parents), l.pdg, l.state) for l in mapping_information['additional_recoilers']) all_recoilers = sub.SubtractionLegSet( list(reduced_recoilers) + list(additional_recoilers)) # Now recursively apply leg numbers mappings mapping_singular_structure = mapping_information[ 'singular_structure'].get_copy() self.map_leg_numbers_in_singular_structure( mapping_singular_structure, overall_parents) # Now assign the recoilers (whose leg numbers have already been mapped) mapping_singular_structure.legs = all_recoilers # Build the momenta_dict by also substituting leg numbers this_momenta_dict = bidict({ self.map_leg_number(k, overall_parents): frozenset([self.map_leg_number(n, overall_parents) for n in v]) for k, v in mapping_information['momenta_dict'].items() }) lower_PS_point, mapping_vars = mapping_information[ 'mapping'].map_to_lower_multiplicity( all_steps[-1]['higher_PS_point'], mapping_singular_structure, this_momenta_dict, compute_jacobian=self.divide_by_jacobian) if mappings.RelabellingMapping.needs_relabelling( this_momenta_dict): lower_PS_point = mappings.RelabellingMapping.map_to_lower_multiplicity( lower_PS_point, None, this_momenta_dict) all_steps[-1]['lower_PS_point'] = lower_PS_point # Q is provided externally mapping_vars.pop('Q', None) all_steps[-1]['mapping_vars'] = mapping_vars overall_jacobian *= mapping_vars.get('jacobian', 1.) bundles_info = [] for bundle in mapping_singular_structure.substructures: bundles_info.append({}) all_legs = bundle.get_all_legs() # This sorting is important so that the variables generated can be related to the legs specified # in the mapping singular structures of the mapping rules all_initial_legs = sorted( [l for l in all_legs if l.state == l.INITIAL], key=lambda l: l.n) all_final_legs = sorted( [l for l in all_legs if l.state == l.FINAL], key=lambda l: l.n) bundles_info[-1]['initial_state_children'] = tuple( l.n for l in all_initial_legs) bundles_info[-1]['final_state_children'] = tuple( l.n for l in all_final_legs) if self.has_parent(bundle, len(all_legs)): bundles_info[-1]['parent'] = self.get_parent( frozenset(l.n for l in all_legs), this_momenta_dict) else: bundles_info[-1]['parent'] = None # Retrieve kinematics bundles_info[-1]['cut_inputs'] = {} if bundle.name() == 'C': if len(all_initial_legs) > 0: bundles_info[-1]['cut_inputs']['pA'] = -sum( all_steps[-1]['higher_PS_point'][l.n] for l in all_initial_legs) bundles_info[-1]['cut_inputs']['pC'] = sum( all_steps[-1]['higher_PS_point'][l.n] for l in all_final_legs) elif bundle.name() == 'S': bundles_info[-1]['cut_inputs']['pS'] = sum( all_steps[-1]['higher_PS_point'][l.n] for l in all_final_legs) all_steps[-1]['bundles_info'] = bundles_info # Get all variables for this level if mapping_information['variables'] is not None: all_steps[-1]['variables'] = mapping_information['variables']( all_steps[-1]['higher_PS_point'], all_steps[-1]['lower_PS_point'], bundles_info, Q=Q, **mapping_vars) else: all_steps[-1]['variables'] = {} # Add the next higher PS point for the next level if necessary if i_step < (len(self.mapping_rules) - 1): all_steps.append({'higher_PS_point': lower_PS_point}) overall_lower_PS_point = all_steps[-1]['lower_PS_point'] reduced_kinematics = (None, overall_lower_PS_point) global_variables = { 'overall_children': overall_children, 'overall_parents': overall_parents, 'leg_numbers_map': self.leg_numbers_map, 'Q': Q, } # Build global variables if necessary if self.variables is not None: global_variables.update(self.variables(all_steps, global_variables)) # Apply cuts: include the counterterm only in a part of the phase-space for i_step, step_info in enumerate(all_steps): cut_inputs = dict(step_info) if self.mapping_rules[i_step]['is_cut'](cut_inputs, global_variables): return utils.SubtractionCurrentResult.zero( current=current, hel_config=hel_config, reduced_kinematics=('IS_CUT', overall_lower_PS_point)) # for i_step, step_info in enumerate(all_steps): # misc.sprint("Higher PS point at step #%d: %s"%(i_step, str(step_info['higher_PS_point']))) # misc.sprint("Lower PS point at step #%d: %s"%(i_step, str(step_info['lower_PS_point']))) # Evaluate kernel evaluation = utils.SubtractionCurrentEvaluation({ 'spin_correlations': [ None, ], 'color_correlations': [ None, ], 'reduced_kinematics': [ reduced_kinematics, ], 'values': {} }) # Apply collinear kernel (can be dummy) evaluation = self.kernel(evaluation, all_steps, global_variables) # Apply soft kernel (can be dummy), which also knows about the reduced process evaluation = self.call_soft_kernel(evaluation, reduced_process, all_steps, global_variables) # Add the normalization factors # WARNING! In this implementation the propagator denominators must be included in the kernel evaluation. norm = (8. * math.pi * alpha_s)**(self.squared_orders['QCD'] / 2) norm /= overall_jacobian for k in evaluation['values']: for term in evaluation['values'][k]: evaluation['values'][k][term] *= 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