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

Use nnpdf single-truth theory #169

Merged
merged 18 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ jobs:
files: ./coverage.xml
flags: bench
name: codecov-umbrella
fail_ci_if_error: true
fail_ci_if_error: false
22 changes: 15 additions & 7 deletions docs/source/overview/prerequisites.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,47 @@ This is a standard example:
[paths]
# inputs
grids = "data/grids"
theory_cards = "data/theory_cards"
operator_card_template_name = "_template.yaml"
# outputs
operator_cards = "data/operator_cards"
ekos = "data/ekos"
fktables = "data/fktables"

# The following two keys are only necessary when nnpdf=false
#theory_cards = "data/theory_cards"
#ymldb = "data/yamldb"

[paths.logs]
eko = "logs/eko"
fk = "logs/fk"


All the relevant inputs are described below. The command ``pineko scaffold new`` will generate all necessary folders.


Theory Runcards
---------------

You need to provide the necessary theory runcards named with their respective theory ID inside the *paths.theory_cards* folder [1]_ unless you are using the ``nnpdf`` key (see below).
For more details about theory runcards you can look at https://docs.nnpdf.science/theory/theoryparamsdefinitions.html

nnpdf
-----
The key ``nnpdf`` tells ``pineko`` it should use the data files from NNPDF to map datasets to FK Tables.
The key ``nnpdf`` tells ``pineko`` it should use the data files from NNPDF to map datasets to FK Tables
and to define the theory parameters.
If this key is given, a valid installation of ``nnpdf`` needs to be available as well.
i.e, ``pineko`` should be installed with the ``nnpdf`` extra (``pip install pineko[nnpdf]``).

Alternatively, it is possible not to set this key (or set it to false) and instead
provide a path with ``yaml`` files containing such dataset-FK mapping.
provide a path with ``yaml`` files containing such dataset-FK mapping or theory cards.
If a custom database of mappings is to be used, the path to the folder containing
this files needs to be explicitly provided:

::

[paths]
ymldb = "data/yamldb"
theory_cards = "data/theory_cards"

These `yaml` files (which should be named `<dataset>.yaml`)
define a mapping from datasets to FK tables.
Expand All @@ -64,11 +76,7 @@ In ``operands`` all the necessary FK tables for the ``target_dataset`` are liste
``NULL`` which means that the FK tables will just be concatenated but other kinds of operations
can be used (for instance ``ratio``).

Theory Runcards
---------------

You need to provide the necessary theory runcards named with their respective theory ID inside the *paths.theory_cards* folder [1]_.
For more details about theory runcards you can look at https://eko.readthedocs.io/en/latest/code/IO.html under **Theory Runcards**.

Default Operator Card
---------------------
Expand Down
34 changes: 34 additions & 0 deletions docs/source/overview/running.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,37 @@ With the command ``pineko compare`` it is possible to compare the predictions as

again eventually specifying the values of *renormalization* and *factorization* scales with the
appropriate options.

Using pineko with NNPDF
"""""""""""""""""""""""

It is possible to use ``pineko`` without providing a mapping between data and grids
giacomomagni marked this conversation as resolved.
Show resolved Hide resolved
(i.e., without a ``yamldb`` database) or theory cards, by using the data declared in the NNPDF
repository.
scarlehoff marked this conversation as resolved.
Show resolved Hide resolved

In order to do this you need to install ``pineko`` withe ``nnpdf`` extra, which will install
felixhekhorn marked this conversation as resolved.
Show resolved Hide resolved
the latest version from the ``nnpdf`` repository::

pip install pineko[nnpdf]

In order to enable ``pineko`` to read the data from ``nnpdf`` it is necessary to set up
the ``general::nnpdf`` key in the configuration file.
Note that if you do that, both ``theory_cards`` and ``ymldb`` keys become unnecessary,
like in the example below.


.. code-block:: yaml

[general]
nnpdf = true

[paths]
grids = "data/grids"
operator_card_template_name = "../_template.yaml"
operator_cards = "data/operator_cards"
ekos = "data/ekos"
fktables = "data/fktables"

[paths.logs]
eko = "logs/eko"
fk = "logs/fk"
344 changes: 175 additions & 169 deletions poetry.lock

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions src/pineko/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
configs = {}
"Holds loaded configurations"

THEORY_PATH_KEY = "theory_cards"
NEEDED_KEYS = [
"operator_cards",
"grids",
"operator_card_template_name",
"theory_cards",
THEORY_PATH_KEY,
"fktables",
"ekos",
]
Expand Down Expand Up @@ -65,11 +66,17 @@ def enhance_paths(configs_):
if generic_options.get("nnpdf", False):
# Fail as soon as possible
try:
import validphys
import nnpdf_data
except ModuleNotFoundError:
raise ModuleNotFoundError(
"Cannot use `nnpdf=True` without a valid installation of NNPDF"
)
# If ``nnpdf_data`` is available, then override also the theory path
# UNLESS the debug-option ``nnpdf_theory`` is set explicitly to false!
if generic_options.get("nnpdf_theory", True):
from nnpdf_data import theory_cards

configs_["paths"][THEORY_PATH_KEY] = theory_cards
else:
required_keys.append("ymldb")

Expand Down
39 changes: 38 additions & 1 deletion src/pineko/evolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,12 @@ def write_operator_card(pineappl_grid, default_card, card_path, tcard):
xif = 1.0 if sv_method is not None else tcard["XIF"]
# update scale variation method
operators_card["configs"]["scvar_method"] = sv_method
# update initial scale mu0

# Make sure that we are using the theory Q0 and fail if the template has a different one
operators_card["mu0"] = tcard["Q0"]
if default_card.get("mu0") is not None and default_card["mu0"] != tcard["Q0"]:
raise ValueError("Template declares a value of Q0 different from theory")

q2_grid = (xif * xif * muf2_grid).tolist()
masses = np.array([tcard["mc"], tcard["mb"], tcard["mt"]]) ** 2
thresholds_ratios = np.array([tcard["kcThr"], tcard["kbThr"], tcard["ktThr"]]) ** 2
Expand Down Expand Up @@ -162,6 +166,39 @@ def write_operator_card(pineappl_grid, default_card, card_path, tcard):
if "timelike" in kv:
operators_card["configs"]["timelike"] = kv["timelike"] == "True"

# Choose the evolution method according to the theory if the key is included
if "ModEv" in tcard:
opconf = operators_card["configs"]
if tcard["ModEv"] == "TRN":
opconf["evolution_method"] = "truncated"
opconf["ev_op_iterations"] = 1
elif tcard["ModEv"] == "EXA":
opconf["evolution_method"] = "iterate-exact"
if "IterEv" in tcard:
opconf["ev_op_iterations"] = tcard["IterEv"]
elif "ev_op_iterations" not in default_card["configs"]:
raise ValueError(
"EXA used but IterEv not found in the theory card and not ev_op_iterations set in the template"
)

# If the evolution method is defined in the template and it is different, fail
template_method = default_card["configs"].get("evolution_method")
if (
template_method is not None
and template_method != opconf["evolution_method"]
):
raise ValueError(
f"The template and the theory have different evolution method ({template_method} vs {opconf['key']})"
)

# If the change is on the number of iterations, take the template value but warn the user
template_iter = default_card["configs"].get("ev_op_iterations")
if template_iter is not None and template_method != opconf["ev_op_iterations"]:
opconf["ev_op_iterations"] = template_iter
logger.warning(
f"The number of iteration in the theory and template is different, using template value ({template_iter})"
)

# Some safety checks
if (
operators_card["configs"]["evolution_method"] == "truncated"
Expand Down
7 changes: 5 additions & 2 deletions src/pineko/theory.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,11 @@ def eko(self, name, _grid, tcard):
# from the PTO needed for the PDF evolution (and so by EKO). Here we
# ensure that the PTO used in the EKO calculation reflects the real
# perturbative order of the prescription.
if "PTOEKO" in tcard:
if tcard.get("PTOEKO") is not None:
tcard["PTO"] = tcard["PTOEKO"]
# Keys still needed by eko below
scarlehoff marked this conversation as resolved.
Show resolved Hide resolved
tcard["Qedref"] = tcard["Qref"]
tcard["MaxNfAs"] = tcard["MaxNfPdf"]
# The operator card has been already generated in the correct format
# The theory card needs to be converted to a format that eko can use
legacy_class = eko.io.runcards.Legacy(tcard, ocard)
Expand Down Expand Up @@ -386,7 +389,7 @@ def fk(self, name, grid_path, tcard, pdf):
# PTODIS, thus using PTO instead of PTODIS to establish the perturbative
# order would result in the PTODIS terms that correspond to orders
# beyond PTO to be neglected
if "PTODIS" in tcard and "FONLL" in tcard["FNS"]:
if "FONLL" in tcard["FNS"] and tcard.get("PTODIS") is not None:
tcard["PTO"] = tcard["PTODIS"]

# check if grid contains SV if theory is requesting them (in particular
Expand Down
7 changes: 6 additions & 1 deletion src/pineko/theory_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import yaml

from . import configs
from .utils import load_nnpdf_theory


def path(theory_id: int) -> pathlib.Path:
Expand All @@ -22,7 +23,7 @@ def path(theory_id: int) -> pathlib.Path:
theory card path

"""
return configs.configs["paths"]["theory_cards"] / f"{theory_id}.yaml"
return configs.configs["paths"][configs.THEORY_PATH_KEY] / f"{theory_id}.yaml"


def load(theory_id: int) -> Dict[str, Any]:
Expand All @@ -39,6 +40,10 @@ def load(theory_id: int) -> Dict[str, Any]:
theory card

"""
nnpdf_theory = load_nnpdf_theory(theory_id, configs.configs)
if nnpdf_theory is not None:
return nnpdf_theory

with open(path(theory_id), encoding="utf-8") as f:
theory_card = yaml.safe_load(f)
return theory_card
Expand Down
34 changes: 30 additions & 4 deletions src/pineko/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
Common tools typically used by several pineko functions.
"""

from .configs import GENERIC_OPTIONS
from .configs import GENERIC_OPTIONS, THEORY_PATH_KEY


def _nnpdf_enabled(configs):
"""Check whether NNPDF is enabled."""
if configs is None:
return True
return configs.get(GENERIC_OPTIONS, {}).get("nnpdf", False)


def read_grids_from_nnpdf(dataset_name, configs=None):
Expand All @@ -18,9 +25,8 @@ def read_grids_from_nnpdf(dataset_name, configs=None):
dictionary of configuration options
if None it it assumed that the NNPDF version is required
"""
if configs is not None:
if not configs.get(GENERIC_OPTIONS, {}).get("nnpdf", False):
return None
if not _nnpdf_enabled(configs):
return None

# Import NNPDF only if we really want it!
from nnpdf_data import legacy_to_new_map
Expand All @@ -33,3 +39,23 @@ def read_grids_from_nnpdf(dataset_name, configs=None):
fks = cd.metadata.theory.FK_tables
# Return it flat
return [f"{i}.{EXT}" for operand in fks for i in operand]


def load_nnpdf_theory(theory_id, configs):
"""Load a theory using the NNPDF data utilities.

If NNPDF is not available, returns None.

Parameters
----------
theory_id: int
configs: dict
dictionary of configuration options
"""
if not _nnpdf_enabled(configs):
return None

from nnpdf_data.theorydbutils import fetch_theory

theory_path = configs["paths"][THEORY_PATH_KEY]
return fetch_theory(theory_path, theory_id)
16 changes: 8 additions & 8 deletions tests/test_evolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,22 @@ def test_write_operator_card_q0(tmp_path):
"""Checks https://github.com/NNPDF/pineko/issues/146"""
p = tmp_path / "q0.yaml"
g = FakePine()
# 1. defaults
t = copy.deepcopy(default_card)
o = copy.deepcopy(example.raw_operator())
# 1. Same Q0 and mu0, all ok
t["Q0"] = 5.0
o["mu0"] = 5.0
_xs, _mu2s = pineko.evolve.write_operator_card(g, o, p, t)
with open(p, encoding="utf8") as f:
oo = yaml.safe_load(f)
np.testing.assert_allclose(oo["mu0"], t["Q0"])
# 2. overwriting from theory side
t["Q0"] = 10.0
# 2. Q0 only in theory, all ok
o.pop("mu0")
_xs, _mu2s = pineko.evolve.write_operator_card(g, o, p, t)
with open(p, encoding="utf8") as f:
oo = yaml.safe_load(f)
np.testing.assert_allclose(oo["mu0"], t["Q0"])
# 3. op template is ignored
# 3. op is different, raises error
o["mu0"] = 11.0
_xs, _mu2s = pineko.evolve.write_operator_card(g, o, p, t)
with open(p, encoding="utf8") as f:
oo = yaml.safe_load(f)
np.testing.assert_allclose(oo["mu0"], t["Q0"])
with pytest.raises(ValueError):
_xs, _mu2s = pineko.evolve.write_operator_card(g, o, p, t)
Loading