Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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)
Пример #5
0
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
Пример #6
0
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
Пример #7
0
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
Пример #8
0
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
Пример #9
0
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
Пример #10
0
    def get_recoilers(cls, counterterm, exclude=None):
        """Select particles in the reduced process to be used as recoilers."""

        legs = counterterm.process['legs']
        model = counterterm.process['model']
        recoilers = [
            sub.SubtractionLeg(leg) for leg in legs if
            cls.good_recoiler(model, leg) and cls.not_excluded(leg, exclude)
        ]
        return recoilers
Пример #11
0
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
Пример #12
0
    def generate_PS_point(cls, process):
        """Generate a phase-space point to test the walker."""

        model = process.get('model')
        # Generate random vectors
        my_PS_point = LorentzVectorDict()
        legs_FS = tuple(
            subtraction.SubtractionLeg(leg) for leg in process['legs']
            if leg['state'] == FINAL)
        for leg in legs_FS:
            my_PS_point[leg.n] = random_momentum(
                simple_qcd.masses[model.get_particle(leg.pdg)['mass']])
        total_momentum = LorentzVector()
        for leg in legs_FS:
            total_momentum += my_PS_point[leg.n]
        legs_IS = tuple(
            subtraction.SubtractionLeg(leg) for leg in process['legs']
            if leg['state'] == INITIAL)
        if len(legs_IS) == 1:
            my_PS_point[legs_IS[0].n] = total_momentum
        elif len(legs_IS) == 2:
            if cls.initial_along_z:
                bv = total_momentum.boostVector()
                for key in my_PS_point.keys():
                    my_PS_point[key].boost(-bv)
                total_momentum.boost(-bv)
                E = total_momentum[0]
                my_PS_point[1] = LorentzVector([E / 2., 0., 0., +E / 2.])
                my_PS_point[2] = LorentzVector([E / 2., 0., 0., -E / 2.])
            else:
                E = abs(total_momentum.square())**0.5
                rest_momentum = LorentzVector([E, 0., 0., 0.])
                my_PS_point[1] = LorentzVector([E / 2., 0., 0., +E / 2.])
                my_PS_point[2] = LorentzVector([E / 2., 0., 0., -E / 2.])
                my_PS_point[1].rotoboost(rest_momentum, total_momentum)
                my_PS_point[2].rotoboost(rest_momentum, total_momentum)
        else:
            raise BaseException
        return my_PS_point
Пример #13
0
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
Пример #14
0
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
Пример #15
0
    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)
Пример #16
0
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
Пример #17
0
    def leg(i):

        return sub.SubtractionLeg(i, 0, sub.SubtractionLeg.FINAL)
Пример #18
0
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
Пример #19
0
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
Пример #20
0
    def _test_approach_limit(self, walker, process,
                             max_unresolved_in_elementary,
                             max_unresolved_in_combination):
        """Check that the walker is capable of approaching limits.

        :param walker: Mapping walker to be tested
        :type walker: walkers.VirtualWalker

        :param process: The physical process the walker will be tested for
        :type process: base_objects.Process

        :param max_unresolved_in_elementary: Maximum number of unresolved particles
        within the same elementary operator
        :type max_unresolved_in_elementary: positive integer

        :param max_unresolved_in_combination: Maximum number of unresolved particles
        within a combination of elementary operators
        :type max_unresolved_in_combination: positive integer
        """

        if self.verbosity > 2:
            print "\n" + self.stars * (self.verbosity - 2)
        if self.verbosity > 0:
            tmp_str = "test_approach_limit for " + walker.__class__.__name__
            tmp_str += " with " + process.nice_string()
            print tmp_str
        if self.verbosity > 2:
            print self.stars * (self.verbosity - 2) + "\n"
        random.seed(self.seed)
        # Generate all counterterms for this process, and separate the non-singular one
        my_operators = self.irs.get_all_elementary_operators(
            process, max_unresolved_in_elementary)
        my_combinations = self.irs.get_all_combinations(
            my_operators, max_unresolved_in_combination)
        my_counterterms = [
            self.irs.get_counterterm(combination, process)
            for combination in my_combinations
        ]
        # Get all legs in the FS and the model to check masses after approach_limit
        legs_FS = tuple(
            subtraction.SubtractionLeg(leg) for leg in process['legs']
            if leg['state'] == FINAL)
        model = process.get('model')
        # For each counterterm
        for ct in my_counterterms:
            if not ct.is_singular():
                continue
            if self.verbosity > 3:
                print "\n" + self.stars * (self.verbosity - 3)
            if self.verbosity > 1: print "Considering counterterm", ct
            if self.verbosity > 3:
                print self.stars * (self.verbosity - 3) + "\n"
            ss = ct.reconstruct_complete_singular_structure()
            for j in range(self.n_test_invertible):
                if self.verbosity > 2:
                    print "Phase space point #", j + 1
                # Generate random vectors
                my_PS_point = self.generate_PS_point(process)
                if self.verbosity > 3:
                    print "Starting phase space point:\n", my_PS_point, "\n"
                squares = {
                    key: my_PS_point[key].square()
                    for key in my_PS_point.keys()
                }
                # Compute collinear variables
                for alpha in self.parameter_values:
                    new_PS_point = walker.approach_limit(
                        my_PS_point, ss, alpha, process)
                    if self.verbosity > 4:
                        print "New PS point for", alpha, ":\n", new_PS_point
                    for leg in legs_FS:
                        if model.get_particle(
                                leg.pdg)['mass'].lower() == 'zero':
                            self.assertLess(abs(new_PS_point[leg.n].square()),
                                            math.sqrt(new_PS_point[leg.n].eps))
                        else:
                            self.assertAlmostEqual(
                                new_PS_point[leg.n].square(), squares[leg.n])
Пример #21
0
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
Пример #22
0
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
Пример #23
0
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
Пример #24
0
 def L(n, state=FINAL):
     return subtraction.SubtractionLeg(n, 0, state)
Пример #25
0
 def dummy_leg(i):
     return subtraction.SubtractionLeg(i, 21, subtraction.SubtractionLeg.FINAL)
Пример #26
0
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
Пример #27
0
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
Пример #28
0
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
Пример #29
0
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
Пример #30
0
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