Top

wilson.util.wet_jms module

Utility functions and dictionaries useful for the manipulation of WET Wilson coefficients.

"""Utility functions and dictionaries useful for the manipulation of WET Wilson coefficients.
"""

from wilson import wcxf
import numpy as np
import ckmutil
from wilson.util import smeftutil


# names of Wilson coefficients with the same fermionic symmetry properties
# numbering is inspired by the corresponding categorization in SMEFT
C_symm_keys = {}
# 0 0F scalar object
C_symm_keys[0] = ["G", "Gtilde"]
# 1 2F general 3x3 matrix
C_symm_keys[1] = ["egamma", "uG","dG", "ugamma", "dgamma"]
# 3 4F general 3x3x3x3 object
C_symm_keys[3] = ['S1udRR', 'S1udduRR', 'S8udRR', 'S8udduRR', 'SedRL',
'SedRR', 'SeuRL', 'SeuRR', 'SnueduRL', 'SnueduRR', 'TedRR', 'TeuRR',
'TnueduRR', 'V1udduLR', 'V8udduLR', 'VnueduLL', 'VnueduLR',
'SuddLL', 'SduuLL', 'SduuLR', 'SduuRL', 'SdudRL', 'SduuRR',]
# 4 4F two identical ffbar currents
# hermitian currents
C_symm_keys[4] = ['VuuRR', 'VddRR', 'VuuLL', 'VddLL']
# non-hermitian currents
C_symm_keys[41] = ['S1ddRR', 'S1uuRR', 'S8uuRR', 'SeeRR', 'S8ddRR']
# 5 4F two independent ffbar currents, hermitian
C_symm_keys[5] = ["VnueLL", "VnuuLL", "VnudLL", "VeuLL", "VedLL", "V1udLL",
        "V8udLL", "VeuRR", "VedRR", "V1udRR", "V8udRR", "VnueLR",
        "VeeLR", "VnuuLR", "VnudLR", "VeuLR", "VedLR", "VueLR", "VdeLR",
        "V1uuLR", "V8uuLR", "V1udLR", "V8udLR", "V1duLR", "V8duLR",
        "V1ddLR", "V8ddLR"]
# 6 4F two identical ffbar currents + Fierz symmetry
C_symm_keys[6] = ['VeeLL', 'VeeRR', 'VnunuLL']
# 4F antisymmetric in first 2 indices
C_symm_keys[71] = ['SuudLR', 'SuudRL', 'SdduRL']


# symmetrize JMS basis

def _scalar2array(d):
    """Convert a dictionary with scalar elements and string indices '_1234'
    to a dictionary of arrays. Unspecified entries are np.nan."""
    da = {}
    for k, v in d.items():
        if '_' not in k:
            da[k] = v
        else:
            name = ''.join(k.split('_')[:-1])
            ind = k.split('_')[-1]
            dim = len(ind)
            if name not in da:
                shape = tuple(3 for i in range(dim))
                da[name] = np.empty(shape, dtype=complex)
                da[name][:] = np.nan
            da[name][tuple(int(i) - 1 for i in ind)] = v
    return da


def _symm_herm(C):
    """To get rid of NaNs produced by _scalar2array, symmetrize operators
    where C_ijkl = C_jilk*"""
    nans = np.isnan(C)
    C[nans] = np.einsum('jilk', C)[nans].conj()
    return C


def _symm_current(C):
    """To get rid of NaNs produced by _scalar2array, symmetrize operators
    where C_ijkl = C_klij"""
    nans = np.isnan(C)
    C[nans] = np.einsum('klij', C)[nans]
    return C

def _antisymm_12(C):
    """To get rid of NaNs produced by _scalar2array, antisymmetrize the first
    two indices of operators where C_ijkl = -C_jikl"""
    nans = np.isnan(C)
    C[nans] = -np.einsum('jikl', C)[nans]
    return C


def JMS_to_array(C, sectors=None):
    """For a dictionary with JMS Wilson coefficients, return a dictionary
    of arrays."""
    if sectors is None:
        wc_keys = wcxf.Basis['WET', 'JMS'].all_wcs
    else:
        try:
            wc_keys = [k for s in sectors for k in wcxf.Basis['WET', 'JMS'].sectors[s]]
        except KeyError:
            print(sectors)
    # fill in zeros for missing coefficients
    C_complete = {k: C.get(k, 0) for k in wc_keys}
    Ca = _scalar2array(C_complete)
    for k in Ca:
        if k in C_symm_keys[5]:
            Ca[k] = _symm_herm(Ca[k])
        if k in C_symm_keys[41]:
            Ca[k] = _symm_current(Ca[k])
        if k in C_symm_keys[4]:
            Ca[k] = _symm_herm(_symm_current(Ca[k]))
        if k in C_symm_keys[71]:
            Ca[k] = _antisymm_12(Ca[k])
    return Ca


def symmetrize_JMS_dict(C):
    """For a dictionary with JMS Wilson coefficients but keys that might not be
    in the non-redundant basis, return a dictionary with keys from the basis
    and values conjugated if necessary."""
    wc_keys = set(wcxf.Basis['WET', 'JMS'].all_wcs)
    Cs = {}
    for op, v in C.items():
        if '_' not in op or op in wc_keys:
            Cs[op] = v
            continue
        name, ind = op.split('_')
        if name in C_symm_keys[5]:
            i, j, k, l = ind
            indnew = ''.join([j, i, l, k])
            Cs['_'.join([name, indnew])] = v.conjugate()
        elif name in C_symm_keys[41]:
            i, j, k, l = ind
            indnew = ''.join([k, l, i, j])
            Cs['_'.join([name, indnew])] = v
        elif name in C_symm_keys[4]:
            i, j, k, l = ind
            indnew = ''.join([l, k, j, i])
            newname = '_'.join([name, indnew])
            if newname in wc_keys:
                Cs[newname] = v.conjugate()
            else:
                indnew = ''.join([j, i, l, k])
                newname = '_'.join([name, indnew])
                if newname in wc_keys:
                    Cs[newname] = v.conjugate()
                else:
                    indnew = ''.join([k, l, i, j])
                    newname = '_'.join([name, indnew])
                    Cs[newname] = v
        elif name in C_symm_keys[71]:
            i, j, k, l = ind
            indnew = ''.join([j, i, k, l])
            Cs['_'.join([name, indnew])] = -v
    return Cs


def rotate_down(C_in, p):
    """Redefinition of all Wilson coefficients in the JMS basis when rotating
    down-type quark fields from the flavour to the mass basis.

    C_in is expected to be an array-valued dictionary containg a key
    for all Wilson coefficient matrices."""
    C = C_in.copy()
    V = ckmutil.ckm.ckm_tree(p["Vus"], p["Vub"], p["Vcb"], p["delta"])
    UdL = V
    ## B conserving operators
    # type dL dR (dipoles)
    for k in ['dgamma', 'dG']:
        C[k] = np.einsum('ia,ij->aj',
                         UdL.conj(),
                         C_in[k])
    # type dL dL dL dL
    for k in ['VddLL']:
        C[k] = np.einsum('ia,jb,kc,ld,ijkl->abcd',
                         UdL.conj(), UdL, UdL.conj(), UdL,
                         C_in[k])
    # type X X dL dL
    for k in ['V1udLL', 'V8udLL', 'VedLL', 'VnudLL']:
        C[k] = np.einsum('kc,ld,ijkl->ijcd',
                         UdL.conj(), UdL,
                         C_in[k])
    # type dL dL X X
    for k in ['V1ddLR', 'V1duLR', 'V8ddLR', 'V8duLR', 'VdeLR']:
        C[k] = np.einsum('ia,jb,ijkl->abkl',
                         UdL.conj(), UdL,
                         C_in[k])
    # type dL X dL X
    for k in ['S1ddRR', 'S8ddRR']:
        C[k] = np.einsum('ia,kc,ijkl->ajcl',
                         UdL.conj(), UdL.conj(),
                         C_in[k])
    # type X dL X X
    for k in ['V1udduLR', 'V8udduLR']:
        C[k] = np.einsum('jb,ijkl->ibkl',
                         UdL,
                         C_in[k])
    # type X X dL X
    for k in ['VnueduLL', 'SedRR', 'TedRR', 'SnueduRR', 'TnueduRR',
              'S1udRR',  'S8udRR', 'S1udduRR',  'S8udduRR', ]:
        C[k] = np.einsum('kc,ijkl->ijcl',
                         UdL.conj(),
                         C_in[k])
    # type X X X dL
    for k in ['SedRL', ]:
        C[k] = np.einsum('ld,ijkl->ijkd',
                         UdL,
                         C_in[k])
    ## DeltaB=DeltaL=1 operators
    # type dL X X X
    for k in ['SduuLL',  'SduuLR']:
        C[k] = np.einsum('ia,ijkl->ajkl',
                         UdL,
                         C_in[k])
    # type X X dL X
    for k in ['SuudRL', 'SdudRL']:
        C[k] = np.einsum('kc,ijkl->ijcl',
                         UdL,
                         C_in[k])
    # type X dL dL X
    for k in ['SuddLL']:
        C[k] = np.einsum('jb,kc,ijkl->ibcl',
                         UdL, UdL,
                         C_in[k])
    return C


_scale_dict = {}
for k in C_symm_keys[0]:
    _scale_dict[k] = 1
for k in C_symm_keys[1]:
    _scale_dict[k] = np.ones((3, 3))
for k in C_symm_keys[3] + C_symm_keys[5]:
    _scale_dict[k] = np.ones((3, 3, 3, 3))
for k in C_symm_keys[4] + C_symm_keys[41]:
    _scale_dict[k] = smeftutil._d_4
for k in C_symm_keys[6]:
    _scale_dict[k] = smeftutil._d_6
for k in C_symm_keys[71]:
    # while _d_7 contains the symmetry factors for the case of coefficients
    # *symmetric* under the 1st 2 indices, they are actually the same as for
    # the case where they are *antisymmetric*
    _scale_dict[k] = smeftutil._d_7


def scale_dict_wet(C):
    """To account for the fact that arXiv:Jenkins:2017jig uses a flavour
    non-redundant basis in contrast to WCxf, symmetry factors of two have to
    be introduced in several places for operators that are symmetric
    under the interchange of two currents."""
    return {k: v / _scale_dict[k] for k, v in C.items()}


def unscale_dict_wet(C):
    """Undo the scaling applied in `scale_dict_wet`."""
    return {k: _scale_dict[k] * v for k, v in C.items()}

Module variables

var C_symm_keys

var k

Functions

def JMS_to_array(

C, sectors=None)

For a dictionary with JMS Wilson coefficients, return a dictionary of arrays.

def JMS_to_array(C, sectors=None):
    """For a dictionary with JMS Wilson coefficients, return a dictionary
    of arrays."""
    if sectors is None:
        wc_keys = wcxf.Basis['WET', 'JMS'].all_wcs
    else:
        try:
            wc_keys = [k for s in sectors for k in wcxf.Basis['WET', 'JMS'].sectors[s]]
        except KeyError:
            print(sectors)
    # fill in zeros for missing coefficients
    C_complete = {k: C.get(k, 0) for k in wc_keys}
    Ca = _scalar2array(C_complete)
    for k in Ca:
        if k in C_symm_keys[5]:
            Ca[k] = _symm_herm(Ca[k])
        if k in C_symm_keys[41]:
            Ca[k] = _symm_current(Ca[k])
        if k in C_symm_keys[4]:
            Ca[k] = _symm_herm(_symm_current(Ca[k]))
        if k in C_symm_keys[71]:
            Ca[k] = _antisymm_12(Ca[k])
    return Ca

def rotate_down(

C_in, p)

Redefinition of all Wilson coefficients in the JMS basis when rotating down-type quark fields from the flavour to the mass basis.

C_in is expected to be an array-valued dictionary containg a key for all Wilson coefficient matrices.

def rotate_down(C_in, p):
    """Redefinition of all Wilson coefficients in the JMS basis when rotating
    down-type quark fields from the flavour to the mass basis.

    C_in is expected to be an array-valued dictionary containg a key
    for all Wilson coefficient matrices."""
    C = C_in.copy()
    V = ckmutil.ckm.ckm_tree(p["Vus"], p["Vub"], p["Vcb"], p["delta"])
    UdL = V
    ## B conserving operators
    # type dL dR (dipoles)
    for k in ['dgamma', 'dG']:
        C[k] = np.einsum('ia,ij->aj',
                         UdL.conj(),
                         C_in[k])
    # type dL dL dL dL
    for k in ['VddLL']:
        C[k] = np.einsum('ia,jb,kc,ld,ijkl->abcd',
                         UdL.conj(), UdL, UdL.conj(), UdL,
                         C_in[k])
    # type X X dL dL
    for k in ['V1udLL', 'V8udLL', 'VedLL', 'VnudLL']:
        C[k] = np.einsum('kc,ld,ijkl->ijcd',
                         UdL.conj(), UdL,
                         C_in[k])
    # type dL dL X X
    for k in ['V1ddLR', 'V1duLR', 'V8ddLR', 'V8duLR', 'VdeLR']:
        C[k] = np.einsum('ia,jb,ijkl->abkl',
                         UdL.conj(), UdL,
                         C_in[k])
    # type dL X dL X
    for k in ['S1ddRR', 'S8ddRR']:
        C[k] = np.einsum('ia,kc,ijkl->ajcl',
                         UdL.conj(), UdL.conj(),
                         C_in[k])
    # type X dL X X
    for k in ['V1udduLR', 'V8udduLR']:
        C[k] = np.einsum('jb,ijkl->ibkl',
                         UdL,
                         C_in[k])
    # type X X dL X
    for k in ['VnueduLL', 'SedRR', 'TedRR', 'SnueduRR', 'TnueduRR',
              'S1udRR',  'S8udRR', 'S1udduRR',  'S8udduRR', ]:
        C[k] = np.einsum('kc,ijkl->ijcl',
                         UdL.conj(),
                         C_in[k])
    # type X X X dL
    for k in ['SedRL', ]:
        C[k] = np.einsum('ld,ijkl->ijkd',
                         UdL,
                         C_in[k])
    ## DeltaB=DeltaL=1 operators
    # type dL X X X
    for k in ['SduuLL',  'SduuLR']:
        C[k] = np.einsum('ia,ijkl->ajkl',
                         UdL,
                         C_in[k])
    # type X X dL X
    for k in ['SuudRL', 'SdudRL']:
        C[k] = np.einsum('kc,ijkl->ijcl',
                         UdL,
                         C_in[k])
    # type X dL dL X
    for k in ['SuddLL']:
        C[k] = np.einsum('jb,kc,ijkl->ibcl',
                         UdL, UdL,
                         C_in[k])
    return C

def scale_dict_wet(

C)

To account for the fact that arXiv:Jenkins:2017jig uses a flavour non-redundant basis in contrast to WCxf, symmetry factors of two have to be introduced in several places for operators that are symmetric under the interchange of two currents.

def scale_dict_wet(C):
    """To account for the fact that arXiv:Jenkins:2017jig uses a flavour
    non-redundant basis in contrast to WCxf, symmetry factors of two have to
    be introduced in several places for operators that are symmetric
    under the interchange of two currents."""
    return {k: v / _scale_dict[k] for k, v in C.items()}

def symmetrize_JMS_dict(

C)

For a dictionary with JMS Wilson coefficients but keys that might not be in the non-redundant basis, return a dictionary with keys from the basis and values conjugated if necessary.

def symmetrize_JMS_dict(C):
    """For a dictionary with JMS Wilson coefficients but keys that might not be
    in the non-redundant basis, return a dictionary with keys from the basis
    and values conjugated if necessary."""
    wc_keys = set(wcxf.Basis['WET', 'JMS'].all_wcs)
    Cs = {}
    for op, v in C.items():
        if '_' not in op or op in wc_keys:
            Cs[op] = v
            continue
        name, ind = op.split('_')
        if name in C_symm_keys[5]:
            i, j, k, l = ind
            indnew = ''.join([j, i, l, k])
            Cs['_'.join([name, indnew])] = v.conjugate()
        elif name in C_symm_keys[41]:
            i, j, k, l = ind
            indnew = ''.join([k, l, i, j])
            Cs['_'.join([name, indnew])] = v
        elif name in C_symm_keys[4]:
            i, j, k, l = ind
            indnew = ''.join([l, k, j, i])
            newname = '_'.join([name, indnew])
            if newname in wc_keys:
                Cs[newname] = v.conjugate()
            else:
                indnew = ''.join([j, i, l, k])
                newname = '_'.join([name, indnew])
                if newname in wc_keys:
                    Cs[newname] = v.conjugate()
                else:
                    indnew = ''.join([k, l, i, j])
                    newname = '_'.join([name, indnew])
                    Cs[newname] = v
        elif name in C_symm_keys[71]:
            i, j, k, l = ind
            indnew = ''.join([j, i, k, l])
            Cs['_'.join([name, indnew])] = -v
    return Cs

def unscale_dict_wet(

C)

Undo the scaling applied in scale_dict_wet.

def unscale_dict_wet(C):
    """Undo the scaling applied in `scale_dict_wet`."""
    return {k: _scale_dict[k] * v for k, v in C.items()}