Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass nl as an argument in qed beta functions #336

Merged
merged 25 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
eb0004c
Pass nl as an argument in qed beta functions
niclaurenti Jan 9, 2024
ecec6f1
Restore check
niclaurenti Jan 9, 2024
16d69f2
Implement varying nl in the coupling running
niclaurenti Jan 9, 2024
3bc4fb7
Fix tests
niclaurenti Jan 9, 2024
0f46f58
Fix test sv
niclaurenti Jan 9, 2024
3628b3f
Fix typo in evolution_operator/init
niclaurenti Jan 9, 2024
bc956e2
Increase rtol to make bench pass
niclaurenti Jan 9, 2024
88c4dcc
Update src/eko/constants.py
niclaurenti Jan 10, 2024
6bcacc4
Update docstring
niclaurenti Jan 10, 2024
ce868a1
Move lepton_number in matchings
niclaurenti Jan 10, 2024
ace95a7
Merge branch 'activate_nl' of github.com:NNPDF/eko into activate_nl
niclaurenti Jan 10, 2024
c493ecc
Add check
niclaurenti Jan 10, 2024
1dc5238
Add check
niclaurenti Jan 10, 2024
1999d92
Call isort on src/eko/evolution_operator/__init__.py
niclaurenti Jan 10, 2024
c4951c7
Add numba decorator
niclaurenti Jan 10, 2024
e561cfd
Update src/eko/matchings.py
niclaurenti Jan 10, 2024
75bfca0
Add docstrings
niclaurenti Jan 10, 2024
b623f97
Force argument to self.nf
niclaurenti Jan 10, 2024
0e85444
Remove debugging print
niclaurenti Jan 11, 2024
efd4562
Add bench for alphaem
niclaurenti Jan 11, 2024
e52d0cd
Add cases in test_beta
niclaurenti Jan 11, 2024
8910ab5
add tests
niclaurenti Jan 11, 2024
981af57
Update benchmarks/eko/benchmark_alphaem.py
niclaurenti Jan 11, 2024
9e23e47
Fix docs of bench_alphaem
niclaurenti Jan 12, 2024
c807ef6
Merge branch 'master' into activate_nl
niclaurenti Jan 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions src/eko/beta.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def beta_qcd_as2(nf):


@nb.njit(cache=True)
def beta_qed_aem2(nf):
def beta_qed_aem2(nf, nl):
niclaurenti marked this conversation as resolved.
Show resolved Hide resolved
r"""Compute the first coefficient of the QED beta function.

Implements Eq. (7) of :cite:`Surguladze:1996hx`.
Expand All @@ -50,7 +50,6 @@ def beta_qed_aem2(nf):
"""
nu = constants.uplike_flavors(nf)
nd = nf - nu
nl = 3 # TODO : pass nl as an argument??
beta_qed_aem2 = (
-4.0 / 3 * (nl + constants.NC * (nu * constants.eu2 + nd * constants.ed2))
)
Expand Down Expand Up @@ -83,7 +82,7 @@ def beta_qcd_as3(nf):


@nb.njit(cache=True)
def beta_qed_aem3(nf):
def beta_qed_aem3(nf, nl):
r"""Compute the second coefficient of the QED beta function.

Implements Eq. (7) of :cite:`Surguladze:1996hx`.
Expand All @@ -101,7 +100,6 @@ def beta_qed_aem3(nf):
"""
nu = constants.uplike_flavors(nf)
nd = nf - nu
nl = 3 # TODO : pass nl as an argument??
beta_qed_aem3 = -4.0 * (
nl + constants.NC * (nu * constants.eu2**2 + nd * constants.ed2**2)
)
Expand Down Expand Up @@ -246,7 +244,7 @@ def beta_qcd(k, nf):


@nb.njit(cache=True)
def beta_qed(k, nf):
def beta_qed(k, nf, nl):
r"""Compute value of a beta_qed coefficients.

Parameters
Expand All @@ -264,9 +262,9 @@ def beta_qed(k, nf):
"""
beta_ = 0
if k == (0, 2):
beta_ = beta_qed_aem2(nf)
beta_ = beta_qed_aem2(nf, nl)
elif k == (0, 3):
beta_ = beta_qed_aem3(nf)
beta_ = beta_qed_aem3(nf, nl)
elif k == (1, 2):
beta_ = beta_qed_aem2as1(nf)
else:
Expand Down Expand Up @@ -295,7 +293,7 @@ def b_qcd(k, nf):


@nb.njit(cache=True)
def b_qed(k, nf):
def b_qed(k, nf, nl):
r"""Compute b_qed coefficient.

Parameters
Expand All @@ -311,4 +309,4 @@ def b_qed(k, nf):
b_qed_k(nf)

"""
return beta_qed(k, nf) / beta_qed((0, 2), nf)
return beta_qed(k, nf, nl) / beta_qed((0, 2), nf, nl)
5 changes: 4 additions & 1 deletion src/eko/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
Defaults to :math:`\frac{N_C^2-1}{2N_C} = 4/3`.
"""

MTAU = 1.777
"""Mass of the tau."""

eu2 = 4.0 / 9
"""Up quarks charge squared."""

Expand Down Expand Up @@ -84,7 +87,7 @@ def uplike_flavors(nf):
nu : int

"""
if nf not in range(2, 6 + 1):
if nf > 6:
giacomomagni marked this conversation as resolved.
Show resolved Hide resolved
raise NotImplementedError("Selected nf is not implemented")
nu = nf // 2
return nu
Expand Down
44 changes: 32 additions & 12 deletions src/eko/couplings.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def expanded_qed(ref, order, beta0, b_vec, lmu):

@nb.njit(cache=True)
def couplings_expanded_alphaem_running(
order, couplings_ref, nf, scale_from, scale_to, decoupled_running
order, couplings_ref, nf, nl, scale_from, scale_to, decoupled_running
):
r"""Compute coupled expanded expression of the couplings for running alphaem.

Expand All @@ -291,6 +291,8 @@ def couplings_expanded_alphaem_running(
reference alpha_s and alpha
nf : int
value of nf for computing the couplings
nl : int
number of leptons partecipating to alphaem running
scale_from : float
reference scale
scale_to : float
Expand All @@ -308,8 +310,8 @@ def couplings_expanded_alphaem_running(
beta0_qcd = beta_qcd((2, 0), nf)
b_vec_qcd = [b_qcd((i + 2, 0), nf) for i in range(order[0])]
res_as = expanded_qcd(couplings_ref[0], order[0], beta0_qcd, b_vec_qcd, lmu)
beta0_qed = beta_qed((0, 2), nf)
b_vec_qed = [b_qed((0, i + 2), nf) for i in range(order[1])]
beta0_qed = beta_qed((0, 2), nf, nl)
b_vec_qed = [b_qed((0, i + 2), nf, nl) for i in range(order[1])]
res_aem = expanded_qed(couplings_ref[1], order[1], beta0_qed, b_vec_qed, lmu)
# if order[0] >= 1 and order[1] >= 1:
# order[0] is always >=1
Expand All @@ -322,7 +324,7 @@ def couplings_expanded_alphaem_running(
)
res_aem += (
-couplings_ref[1] ** 2
* b_qed((1, 2), nf)
* b_qed((1, 2), nf, nl)
* np.log(1 + beta0_qed * couplings_ref[0] * lmu)
)
return np.array([res_as, res_aem])
Expand Down Expand Up @@ -521,7 +523,7 @@ def rge(_t, a, b_vec):
)
return res.y[0][-1]

def compute_exact_alphaem_running(self, a_ref, nf, scale_from, scale_to):
def compute_exact_alphaem_running(self, a_ref, nf, nl, scale_from, scale_to):
"""Compute couplings via |RGE| with running alphaem.

Parameters
Expand All @@ -530,6 +532,8 @@ def compute_exact_alphaem_running(self, a_ref, nf, scale_from, scale_to):
reference alpha_s and alpha
nf : int
value of nf for computing alpha_i
nl : int
number of leptons partecipating to alphaem running
scale_from : float
reference scale
scale_to : float
Expand Down Expand Up @@ -576,12 +580,12 @@ def compute_exact_alphaem_running(self, a_ref, nf, scale_from, scale_to):
# while aem is constant
return np.array([rge_qcd, a_ref[1]])
if self.order[1] >= 1:
beta_qed_vec = [beta_qed((0, 2), nf)]
beta_qed_vec = [beta_qed((0, 2), nf, nl)]
if not self.decoupled_running:
beta_qcd_mix = beta_qcd((2, 1), nf)
beta_qed_mix = beta_qed((1, 2), nf) # order[0] is always at least 1
beta_qed_mix = beta_qed((1, 2), nf, nl) # order[0] is always at least 1
if self.order[1] >= 2:
beta_qed_vec.append(beta_qed((0, 3), nf))
beta_qed_vec.append(beta_qed((0, 3), nf, nl))

# integration kernel
def rge(_t, a, beta_qcd_vec, beta_qcd_mix, beta_qed_vec, beta_qed_mix):
Expand Down Expand Up @@ -656,7 +660,7 @@ def compute_exact_fixed_alphaem(self, a_ref, nf, scale_from, scale_to):
)
return np.array([rge_qcd, a_ref[1]])

def compute(self, a_ref, nf, scale_from, scale_to):
def compute(self, a_ref, nf, nl, scale_from, scale_to):
"""Compute actual couplings.

This is a wrapper in order to pass the computation to the corresponding method
Expand All @@ -668,6 +672,8 @@ def compute(self, a_ref, nf, scale_from, scale_to):
reference a
nf : int
value of nf for computing alpha
nl : int
number of leptons partecipating to alphaem running
scale_from : float
reference scale
scale_to : float
Expand All @@ -678,15 +684,15 @@ def compute(self, a_ref, nf, scale_from, scale_to):
numpy.ndarray
couplings at target scale :math:`a(Q^2)`
"""
key = (float(a_ref[0]), float(a_ref[1]), nf, scale_from, float(scale_to))
key = (float(a_ref[0]), float(a_ref[1]), nf, nl, scale_from, float(scale_to))
try:
return self.cache[key].copy()
except KeyError:
# at the moment everything is expanded - and type has been checked in the constructor
if self.method == "exact":
if self.alphaem_running:
a_new = self.compute_exact_alphaem_running(
a_ref.astype(float), nf, scale_from, scale_to
a_ref.astype(float), nf, nl, scale_from, scale_to
)
else:
a_new = self.compute_exact_fixed_alphaem(
Expand All @@ -698,6 +704,7 @@ def compute(self, a_ref, nf, scale_from, scale_to):
self.order,
a_ref.astype(float),
nf,
nl,
scale_from,
float(scale_to),
self.decoupled_running,
Expand Down Expand Up @@ -737,7 +744,20 @@ def a(
for k, seg in enumerate(path):
# skip a very short segment, but keep the matching
if not np.isclose(seg.origin, seg.target):
new_a = self.compute(final_a, seg.nf, seg.origin, seg.target)
nli = matchings.lepton_number(seg.origin)
nlf = matchings.lepton_number(seg.target)
if self.order[1] != 0 and nli != nlf:
# it means that MTAU is between origin and target:
# first we evolve from origin to MTAU with nli leptons
a_tmp = self.compute(
final_a, seg.nf, nli, seg.origin, constants.MTAU**2
)
# then from MTAU to target with nlf leptons
niclaurenti marked this conversation as resolved.
Show resolved Hide resolved
new_a = self.compute(
a_tmp, seg.nf, nlf, constants.MTAU**2, seg.target
)
else:
new_a = self.compute(final_a, seg.nf, nli, seg.origin, seg.target)
else:
new_a = final_a
# apply matching conditions: see hep-ph/9706430
Expand Down
36 changes: 6 additions & 30 deletions src/eko/evolution_operator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from ..kernels import singlet_qed as qed_s
from ..kernels import utils
from ..kernels import valence_qed as qed_v
from ..matchings import Segment
from ..matchings import Segment, lepton_number
from ..member import OpMember

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -505,7 +505,7 @@ def quad_ker_qed(
# scale var exponentiated is directly applied on gamma
if sv_mode == sv.Modes.exponentiated:
gamma_s = sv.exponentiated.gamma_variation_qed(
gamma_s, order, nf, L, alphaem_running
gamma_s, order, nf, lepton_number(mu2_to), L, alphaem_running
)
ker = qed_s.dispatcher(
order,
Expand Down Expand Up @@ -533,7 +533,7 @@ def quad_ker_qed(
# scale var exponentiated is directly applied on gamma
if sv_mode == sv.Modes.exponentiated:
gamma_v = sv.exponentiated.gamma_variation_qed(
gamma_v, order, nf, L, alphaem_running
gamma_v, order, nf, lepton_number(mu2_to), L, alphaem_running
)
ker = qed_v.dispatcher(
order,
Expand All @@ -558,7 +558,7 @@ def quad_ker_qed(
# scale var exponentiated is directly applied on gamma
if sv_mode == sv.Modes.exponentiated:
gamma_ns = sv.exponentiated.gamma_variation_qed(
gamma_ns, order, nf, L, alphaem_running
gamma_ns, order, nf, lepton_number(mu2_to), L, alphaem_running
)
ker = qed_ns.dispatcher(
order,
Expand Down Expand Up @@ -704,38 +704,14 @@ def compute_aem_list(self):
as_list = np.array([self.a_s[0], self.a_s[1]])
a_half = np.zeros((ev_op_iterations, 2))
else:
as0 = self.a_s[0]
as1 = self.a_s[1]
aem0 = self.a_em[0]
aem1 = self.a_em[1]
q2ref = self.managers["couplings"].mu2_ref
delta_from = abs(self.q2_from - q2ref)
delta_to = abs(self.q2_to - q2ref)
# I compute the values in aem_list starting from the mu2
# that is closer to mu_ref.
if delta_from > delta_to:
a_start = np.array([as1, aem1])
mu2_start = self.q2_to
else:
a_start = np.array([as0, aem0])
mu2_start = self.q2_from
couplings = self.managers["couplings"]
mu2_steps = utils.geomspace(self.q2_from, self.q2_to, 1 + ev_op_iterations)
mu2_l = mu2_steps[0]
as_list = np.array(
[
couplings.compute(
a_ref=a_start, nf=self.nf, scale_from=mu2_start, scale_to=mu2
)[0]
for mu2 in mu2_steps
]
)
as_list = np.array([couplings.a_s(scale_to=mu2) for mu2 in mu2_steps])
a_half = np.zeros((ev_op_iterations, 2))
for step, mu2_h in enumerate(mu2_steps[1:]):
mu2_half = (mu2_h + mu2_l) / 2.0
a_s, aem = couplings.compute(
a_ref=a_start, nf=self.nf, scale_from=mu2_start, scale_to=mu2_half
)
a_s, aem = couplings.a(scale_to=mu2_half)
a_half[step] = [a_s, aem]
mu2_l = mu2_h
return as_list, a_half
Expand Down
22 changes: 22 additions & 0 deletions src/eko/matchings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from dataclasses import dataclass
from typing import List, Union

import numba as nb
import numpy as np

from .constants import MTAU
from .io.types import EvolutionPoint as EPoint
from .io.types import FlavorIndex, FlavorsNumber, SquaredScale
from .quantities.heavy_quarks import MatchingScales
Expand Down Expand Up @@ -209,3 +211,23 @@ def is_downward_path(path: Path) -> bool:
def flavor_shift(is_downward: bool) -> int:
"""Determine the shift to number of light flavors."""
return 4 if is_downward else 3


@nb.njit(cache=True)
def lepton_number(q2):
"""Compute the number of leptons.

Note: muons and electrons are always massless as for up, down and strange.

Parameters
----------
q2 : float
scale

Returns
-------
int :
Number of leptons

"""
return 3 if q2 > MTAU**2 else 2
6 changes: 4 additions & 2 deletions src/eko/scale_variations/exponentiated.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def gamma_variation(gamma, order, nf, L):


@nb.njit(cache=True)
def gamma_variation_qed(gamma, order, nf, L, alphaem_running):
def gamma_variation_qed(gamma, order, nf, nl, L, alphaem_running):
"""Adjust the anomalous dimensions with the scale variations.

Parameters
Expand All @@ -57,6 +57,8 @@ def gamma_variation_qed(gamma, order, nf, L, alphaem_running):
perturbation order
nf : int
number of active flavors
nl : int
number of leptons partecipating to alphaem running
L : float
logarithmic ratio of factorization and renormalization scale

Expand All @@ -71,6 +73,6 @@ def gamma_variation_qed(gamma, order, nf, L, alphaem_running):
gamma[1:, 0] = gamma_variation(gamma[1:, 0], order, nf, L)
if alphaem_running:
if order[1] >= 2:
beta0qed = beta.beta_qed((0, 2), nf)
beta0qed = beta.beta_qed((0, 2), nf, nl)
gamma[0, 2] += beta0qed * gamma[0, 1] * L
return gamma
6 changes: 6 additions & 0 deletions tests/eko/evolution_operator/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ def __init__(self):
def a(self, scale_to=None, nf_to=None):
return (0.1, 0.01)

def a_s(self, scale_to=None, nf_to=None):
return self.a(scale_to, nf_to)[0]

def a_em(self, scale_to=None, nf_to=None):
return self.a(scale_to, nf_to)[1]

def compute(self, a_ref, nf, scale_from, scale_to):
return a_ref

Expand Down
8 changes: 4 additions & 4 deletions tests/eko/scale_variations/test_exponentiated.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ def test_gamma_ns_qed_fact():
[0.15, 0.0, 0.0, 0.0, 0.0],
]
).transpose()
gamma_ns_as1aem1_0 = gamma_variation_qed(gamma_ns.copy(), (1, 1), 3, 0, True)
gamma_ns_as1aem1_0 = gamma_variation_qed(gamma_ns.copy(), (1, 1), 3, 3, 0, True)
np.testing.assert_allclose(gamma_ns_as1aem1_0, gamma_ns)
gamma_ns_as1aem1_1 = gamma_variation_qed(gamma_ns.copy(), (1, 1), 3, -1, True)
gamma_ns_as1aem1_1 = gamma_variation_qed(gamma_ns.copy(), (1, 1), 3, 3, -1, True)
np.testing.assert_allclose(gamma_ns_as1aem1_1, gamma_ns)
gamma_ns_as2aem2_1 = gamma_variation_qed(gamma_ns.copy(), (2, 2), 3, -1, True)
gamma_ns_as2aem2_1 = gamma_variation_qed(gamma_ns.copy(), (2, 2), 3, 3, -1, True)
assert gamma_ns_as2aem2_1[2, 0] < gamma_ns[2, 0]
assert gamma_ns_as2aem2_1[0, 2] > gamma_ns[0, 2] # beta0qed < 0
gamma_ns_as4aem2_1 = gamma_variation_qed(gamma_ns.copy(), (4, 2), 3, -1, True)
gamma_ns_as4aem2_1 = gamma_variation_qed(gamma_ns.copy(), (4, 2), 3, 3, -1, True)
gamma_ns_N3LO_1 = gamma_variation(gamma_ns.copy()[1:, 0], (4, 0), 3, -1)
np.testing.assert_allclose(gamma_ns_as4aem2_1[1:, 0], gamma_ns_N3LO_1)
Loading
Loading