import numbers
import numpy as np
[docs]
class ESFResult:
"""
Represents the output tensor for a single kinematic point
Parameters
----------
x : float
Bjorken x
Q2 : float
virtuality of the exchanged boson
"""
def __init__(self, x, Q2, nf, orders=None):
self.x = x
self.Q2 = Q2
self.nf = nf
self.orders = {} if orders is None else orders
[docs]
@classmethod
def from_document(cls, raw):
"""
Recover element from a raw dictionary
Parameters
----------
raw : dict
raw dictionary
Returns
-------
new_output : cls
object representation
"""
new_output = cls(raw["x"], raw["Q2"], raw["nf"])
for e in raw["orders"]:
new_output.orders[tuple(e["order"])] = (
np.array(e["values"]),
np.array(e["errors"]),
)
return new_output
[docs]
def apply_pdf(self, lhapdf_like, pids, xgrid, alpha_s, alpha_qed, xiR, xiF):
r"""
Compute the observable for the given PDF.
Parameters
----------
lhapdf_like : object
object that provides an xfxQ2 callable (as `lhapdf <https://lhapdf.hepforge.org/>`_
and :class:`ekomark.toyLH.toyPDF` do) (and thus is in flavor basis)
pids : list(int)
list of pids
xgrid : list(float)
interpolation grid
xiF : float
factorization scale ration :math:`\mu_F^2 = Q^2 \xi_F^2` - beware the square!
Returns
-------
res : dict
output dictionary with x, Q2, result and error
"""
if not isinstance(self.Q2, numbers.Number):
raise ValueError("Q2 is not set!")
# factorization scale
muF2 = self.Q2 * xiF**2
pdfs = np.zeros((len(pids), len(xgrid)))
for j, pid in enumerate(pids):
if not lhapdf_like.hasFlavor(pid):
continue
pdfs[j] = np.array([lhapdf_like.xfxQ2(pid, z, muF2) / z for z in xgrid])
# join elements
res = 0
err = 0
# join elements
a_s = alpha_s(np.sqrt(self.Q2) * xiR) / (4 * np.pi)
alph_qed = alpha_qed(np.sqrt(self.Q2) * xiR)
for o, (v, e) in self.orders.items():
lnF = 1.0 if o[3] == 0 else (np.log((1 / xiF) ** 2)) ** o[3]
lnR = 1.0 if o[2] == 0 else (np.log((1 / xiR) ** 2)) ** o[2]
prefactor = (a_s ** o[0]) * (alph_qed ** o[1]) * lnR * lnF
res += prefactor * np.einsum("aj,aj", v, pdfs, optimize="optimal")
err += prefactor * np.einsum("aj,aj", e, pdfs, optimize="optimal")
return dict(x=self.x, Q2=self.Q2, result=res, error=err)
[docs]
def get_raw(self):
"""
Returns the raw data ready for serialization.
Returns
-------
out : dict
output dictionary
"""
try:
nf = int(self.nf)
except TypeError:
nf = self.nf
d = dict(x=float(self.x), Q2=float(self.Q2), nf=nf, orders=[])
for o, (v, e) in self.orders.items():
d["orders"].append(
dict(order=list(o), values=v.tolist(), errors=e.tolist())
)
return d
[docs]
def __add__(self, other):
r = ESFResult(self.x, self.Q2, self.nf)
for o, (v, e) in self.orders.items():
if o in other.orders: # add the common stuff
r.orders[o] = (v + other.orders[o][0], e + other.orders[o][1])
else: # add my stuff
r.orders[o] = (v, e)
for o, (v, e) in other.orders.items():
if o in self.orders:
continue
# add his stuff
r.orders[o] = (v, e)
return r
[docs]
def __sub__(self, other):
return self.__add__(-other)
[docs]
def __neg__(self):
return self.__mul__(-1.0)
[docs]
def __mul__(self, other):
r = ESFResult(self.x, self.Q2, self.nf)
try:
val = other[0]
err = other[1]
except TypeError:
val = other
err = 0
for o, (v, e) in self.orders.items():
r.orders[o] = (val * v, val * e + err * v)
return r
[docs]
def __rmul__(self, other):
return self.__mul__(other)
[docs]
class EXSResult(ESFResult):
def __init__(self, x, Q2, y, nf, orders=None):
super().__init__(x, Q2, nf, orders)
self.y = y
[docs]
@classmethod
def from_document(cls, raw):
sup = ESFResult.from_document(raw)
return cls(sup.x, sup.Q2, raw["y"], sup.nf, sup.orders)
[docs]
def get_raw(self):
d = super().get_raw()
d["y"] = float(self.y)
return d
[docs]
def apply_pdf(self, *args):
res = super().apply_pdf(*args)
res["y"] = self.y
return res