evermore for ATLAS#
If you are coming from the ATLAS experiment, you are probably familiar with the \(\pyhf\) project.
In the following, you will find a brief comparison how modifier types of \(\pyhf\) can be implemented in evermore.
Simple Example (pyhf)#
This is a simple example of a signal process scaled by an unconstrained modifier \(\mu\) and a background process with a normalization uncertainty (normsys).
import pyhf
workspace_json = {
"channels": [
{ "name": "singlechannel",
"samples": [
{ "name": "signal",
"data": [12.0, 11.0],
"modifiers": [ { "name": "mu", "type": "normfactor", "data": None} ]
},
{ "name": "background",
"data": [50.0, 52.0],
"modifiers": [ {"name": "bkg_norm", "type": "normsys", "data": { "hi": 1.1, "lo": 0.9 }} ]
}
]
}
],
"observations": [
{ "name": "singlechannel", "data": [51.0, 48.0] }
],
"measurements": [
{ "name": "Measurement", "config": {"poi": "mu", "parameters": []} }
],
"version": "1.0.0"
}
model = pyhf.Workspace(workspace_json).model()
# eval model to get expectation
model.expected_data(model.config.suggested_init(), include_auxdata=False)
# -> array([62., 63.])
model.expected_data([0.5, 1.12], include_auxdata=False)
# -> array([61.63265822, 63.35796454])
import jax
import jax.numpy as jnp
import evermore as evm
jax.config.update("jax_enable_x64", True)
params = {"mu": evm.Parameter(value=1.0), "bkg_norm": evm.NormalParameter(value=0.0)}
hists = {"signal": jnp.array([12.0, 11.0]), "background": jnp.array([50.0, 52.0])}
data = jnp.array([51.0, 48.0])
def model(params: dict, hists: dict) -> jnp.ndarray:
mu_modifier = params["mu"].scale()
syst_modifier = params["bkg_norm"].scale_log_asymmetric(up=1.1, down=0.9)
return mu_modifier(hists["signal"]) + syst_modifier(hists["background"])
# eval model to get expectation
model(params, hists)
# -> Array([62., 63.], dtype=float64)
model({"mu": evm.Parameter(value=0.5), "bkg_norm": evm.NormalParameter(value=1.12)}, hists)
# -> Array([61.63265822, 63.35796454], dtype=float64)
Modifier types#
For a more detailed overview of modifier types in \(\pyhf\), please refer to the \(\pyhf\) documentation.
Normalisation Uncertainty (normsys)#
See normsys.
{
"name": "mod_name",
"type": "normsys",
"data": { "hi": 1.1, "lo": 0.9 }
}
import jax.numpy as jnp
import evermore as evm
param = evm.NormalParameter()
modifier = evm.Modifier(
parameter=param,
effect=evm.effect.AsymmetricExponential(up=1.1, down=0.9),
)
# or short-hand:
modifier = param.scale_log_asymmetric(up=1.1, down=0.9)
MC Statistical Uncertainty (staterror)#
See staterror.
{
"name": "mod_name",
"type": "staterror",
"data": [0.1]
}
import jax.numpy as jnp
import evermore as evm
param = evm.NormalParameter()
# exemplary histogram with yield=10 and absolute uncertainty=0.1
hist = jnp.array([10.0])
rel_unc = 0.1 / hist
modifier = evm.Modifier(
parameter=param,
effect=evm.effect.Linear(offset=1, slope=rel_unc),
)
# or short-hand:
modifier = param.scale(offset=1, slope=rel_unc)
Luminosity (lumi)#
This modifier type can be implemented in the same way as the normsys modifier
type, see Normalisation Uncertainty (normsys). See
lumi.
Unconstrained Normalisation (normfactor)#
See normfactor.
{
"name": "mod_name",
"type": "normfactor",
"data": null
}
import jax.numpy as jnp
import evermore as evm
param = evm.Parameter()
modifier = evm.Modifier(
parameter=param,
effect=evm.effect.Linear(offset=0, slope=1),
)
# or short-hand:
modifier = param.scale()
Data-driven Shape (shapefactor)#
See shapefactor.
{
"name": "mod_name",
"type": "shapefactor",
"data": null
}
import jax.numpy as jnp
import evermore as evm
# param.value is the shape factor, one value per bin
hist = jnp.array([10.0, 20.0, 30.0])
param = evm.Parameter(value=[0.0, 0.0, 0.0])
modifier = evm.Modifier(
parameter=param,
effect=evm.effect.Linear(offset=0, slope=1),
)
# or short-hand:
modifier = param.scale()