Skip to content

Commit

Permalink
Merge branch 'main' into generate_kfactors
Browse files Browse the repository at this point in the history
  • Loading branch information
toonhasenack committed Feb 20, 2024
2 parents 359b37d + 8f191f8 commit 91c3a1a
Show file tree
Hide file tree
Showing 30 changed files with 1,633 additions and 342 deletions.
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ repos:
- id: check-case-conflict
- id: check-ast
- repo: https://github.com/hadialqattan/pycln
rev: v2.3.0
rev: v2.4.0
hooks:
- id: pycln
args: [--config=pyproject.toml]
- repo: https://github.com/psf/black
rev: 23.9.1
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.1.1
hooks:
- id: black
- repo: https://github.com/asottile/blacken-docs
rev: 1.16.0
hooks:
- id: blacken-docs
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "black"]
Expand All @@ -45,6 +45,6 @@ repos:
additional_dependencies:
- toml
- repo: https://github.com/pre-commit/pre-commit
rev: v3.5.0
rev: v3.6.1
hooks:
- id: validate_manifest
36 changes: 35 additions & 1 deletion benchmarks/bench_evolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,47 @@
import pineappl
import pytest
import yaml
from eko import couplings as sc

import pineko
import pineko.evolve
import pineko.theory_card


@pytest.mark.parametrize("theoryid,is_mixed", [(400, False), (208, True)])
def benchmark_write_operator_card_from_file_num_fonll(
tmp_path, test_files, test_configs, theoryid, is_mixed
):
tcard = pineko.theory_card.load(theoryid)
tcards_path_list = pineko.fonll.dump_tcards(tcard, tmp_path, theoryid)
pine_path = (
test_files
/ "data"
/ "grids"
/ "400"
/ "HERA_NC_225GEV_EP_SIGMARED.pineappl.lz4"
)
default_path = test_files / "data" / "operator_cards" / "400" / "_template.yaml"
num_opcard = 7 if is_mixed else 5
targets_path_list = [
tmp_path / f"test_opcard_{num}.yaml" for num in range(num_opcard)
]
for target_path, tcard_path in zip(targets_path_list, tcards_path_list):
with open(tcard_path, encoding="utf-8") as f:
tcard = yaml.safe_load(f)
_x_grid, _q2_grid = pineko.evolve.write_operator_card_from_file(
pine_path, default_path, target_path, tcard
)
# Check if the opcards are ok
for opcard_path, cfg in zip(
targets_path_list,
pineko.fonll.FNS_CONFIG,
):
with open(opcard_path, encoding="utf-8") as f:
ocard = yaml.safe_load(f)
for entry in ocard["mugrid"]:
assert entry[1] == int(cfg.nf)


def benchmark_write_operator_card_from_file(tmp_path, test_files, test_configs):
pine_path = test_files / "data/grids/400/HERA_NC_225GEV_EP_SIGMARED.pineappl.lz4"
default_path = test_files / "data/operator_cards/400/_template.yaml"
Expand Down
27 changes: 27 additions & 0 deletions benchmarks/bench_fonll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest
import yaml

import pineko


@pytest.mark.parametrize("theoryid,is_mixed", [(400, False), (208, True)])
def benchmark_produce_fonll_tcards(
tmp_path, test_files, test_configs, theoryid, is_mixed
):
tcard = pineko.theory_card.load(theoryid)
tcard_paths_list = pineko.fonll.dump_tcards(tcard, tmp_path, theoryid)
# Check they are correct
theorycards = []
for path in tcard_paths_list:
with open(path, encoding="UTF-8") as f:
theorycards.append(yaml.safe_load(f))
base_pto = pineko.fonll.FNS_BASE_PTO[tcard["FNS"]]
for num_fonll_tcard, cfg in zip(
theorycards,
pineko.fonll.FNS_CONFIG,
):
po = int(base_pto) + (cfg.delta_pto if is_mixed else 0)
assert num_fonll_tcard["FNS"] == cfg.scheme
assert num_fonll_tcard["NfFF"] == int(cfg.nf)
assert num_fonll_tcard["PTO"] == po - 1 if is_mixed and cfg.asy else po
assert num_fonll_tcard["FONLLParts"] == cfg.parts
1 change: 1 addition & 0 deletions benchmarks/bench_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
are downloaded from https://github.com/NNPDF/theories during this test so this tests
has the double effect of ensuring compatibility between both repositories.
"""

import itertools
from pathlib import Path
from subprocess import run
Expand Down
1,146 changes: 847 additions & 299 deletions poetry.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ packages = [{ include = "pineko", from = "src" }]

[tool.poetry.dependencies]
python = ">=3.8,<3.12"
eko = "^0.13.2"
eko = "^0.14.0"
pineappl = "^0.6.2"
PyYAML = "^6.0"
numpy = "^1.21.0"
Expand All @@ -49,6 +49,7 @@ pytest = "^7.1.3"
pytest-cov = "^4.0.0"
pytest-env = "^0.6.2"
pylint = "^2.11.1"
banana-hep = "^0.6.11"

[tool.poetry.group.dev.dependencies]
pdbpp = "^0.10.3"
Expand Down
1 change: 1 addition & 0 deletions src/pineko/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""pineko = PineAPPL + EKO."""

from .cli import command
from .version import __version__
43 changes: 32 additions & 11 deletions src/pineko/check.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tools to check compatibility of EKO and grid."""

from dataclasses import dataclass
from enum import Enum, auto
from typing import Tuple
Expand Down Expand Up @@ -116,29 +117,49 @@ def check_grid_and_eko_compatible(pineappl_grid, operators, xif, max_as, max_al)
raise ValueError("x grid in pineappl grid and eko operator are NOT compatible!")


def is_fonll_b(fns, lumi):
"""Check if the fktable we are computing is a DIS FONLL-B fktable.
def is_dis(lumi):
"""Check if the fktable we are computing is a DIS fktable.
Parameters
----------
fns : str
flavor number scheme (from the theory card)
lumi : list(list(tuple))
luminosity info
Returns
-------
bool
true if the fktable is a FONLL-B DIS fktable
true if the fktable is a DIS fktable
"""
for lists in lumi:
for el in lists:
for entry in lumi:
for el in entry:
if (not islepton(el[0])) and (not islepton(el[1])):
# in this case we are sure it is not DIS so for sure it is not FONLL-B
# If neither of the incoming particles is a lepton we are sure
# it is not DIS
return False
if fns == "FONLL-B":
return True
return False
return True


def is_fonll_mixed(fns, lumi):
"""Check if the fktable we are computing is FONLL-B, FONLL-D or, in general, a mixed FONLL fktable.
Parameters
----------
fns : str
flavor number scheme (from the theory card)
lumi : list(list(tuple))
luminosity info
Returns
-------
bool
true if the fktable is a mixed FONLL DIS fktable
"""
return is_dis(lumi) and fns in ["FONLL-B", "FONLL-D"]


def is_num_fonll(fns):
"""Check if the FNS is a nFONLL FNS."""
return fns in ["FONLL-FFNS", "FONLL-FFN0"]


def orders(grid, max_as, max_al) -> list:
Expand Down
13 changes: 12 additions & 1 deletion src/pineko/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
"""CLI entry point."""
from . import check, compare, convolute, gen_sv, kfactor, opcard, scaffold, theory_

from . import (
check,
compare,
convolute,
fonll,
gen_sv,
kfactor,
opcard,
scaffold,
theory_,
)
from ._base import command
1 change: 1 addition & 0 deletions src/pineko/cli/check.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""CLI entry point to check compatibility."""

from dataclasses import dataclass
from enum import Enum

Expand Down
1 change: 1 addition & 0 deletions src/pineko/cli/compare.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""CLI entry point to comparison grid vs. FK Table."""

import click
import pineappl
import rich
Expand Down
1 change: 1 addition & 0 deletions src/pineko/cli/convolute.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""CLI entry point to convolution."""

import click
import eko
import pineappl
Expand Down
151 changes: 151 additions & 0 deletions src/pineko/cli/fonll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""CLI entry point to FONLL."""

import pathlib

import click
import rich

from .. import configs, fonll, parser, theory_card
from ._base import command

config_setting = click.option(
"-c",
"--configs",
"cfg",
default=None,
type=click.Path(resolve_path=True, path_type=pathlib.Path),
help="Explicitly specify config file (it has to be a valid TOML file).",
)


class TheoryCardError(Exception):
"""Raised when asked for FONLL theory cards with an original tcard as input that is not asking for FONLL."""


class InconsistentInputsError(Exception):
"""Raised if the inputs are not consistent with FONLL."""


def cfgpath(name, grid):
"""Path of the fktable in 'name' called 'grid' if it exists, else None."""
path = configs.configs["paths"]["fktables"] / name / grid
return path if path.exists() else None


def grids_names(yaml_file):
"""Return the list of the grids in the yaml file."""
yaml_content = parser._load_yaml(yaml_file)
# Turn the operands and the members into paths (and check all of them exist)
ret = []
for operand in yaml_content["operands"]:
for member in operand:
ret.append(f"{member}.{parser.EXT}")
return ret


@command.command("combine_fonll")
@click.argument("theoryID", type=int)
@click.argument("dataset", type=str)
@click.option("--FFNS3", type=int, help="theoryID containing the ffns3 fktable")
@click.option("--FFN03", type=int, help="theoryID containing the ffn03 fktable")
@click.option("--FFNS4til", type=int, help="theoryID containing the ffns4til fktable")
@click.option("--FFNS4bar", type=int, help="theoryID containing the ffns4bar fktable")
@click.option("--FFN04", type=int, help="theoryID containing the ffn04 fktable")
@click.option("--FFNS5til", type=int, help="theoryID containing the ffns5til fktable")
@click.option("--FFNS5bar", type=int, help="theoryID containing the ffns5bar fktable")
@click.option("--overwrite", is_flag=True, help="Allow files to be overwritten")
@config_setting
def subcommand(
theoryid,
dataset,
ffns3,
ffn03,
ffns4til,
ffns4bar,
ffn04,
ffns5til,
ffns5bar,
overwrite,
cfg,
):
"""Combine the different FKs needed to produce the FONLL prescription."""
path = configs.detect(cfg)
base_configs = configs.load(path)
configs.configs = configs.defaults(base_configs)
if cfg is not None:
print(f"Configurations loaded from '{path}'")

# Checks

if not ffns3 or not ffn03:
raise InconsistentInputsError("ffns3 and/or ffn03 is not provided.")

if ffns4til is None or ffns4bar is None:
raise InconsistentInputsError(
"At least one of ffns4til and ffns4bar should be provided."
)

# Do we consider two masses, i.e. mc and mb
if any([ffns5til, ffns5bar, ffn04]):
if (ffns5til is None and ffns5bar is None) or ffn04 is None:
raise InconsistentInputsError(
"To include nf5 contributions, ffn04 and at least one between ffns5til and ffns5bar are mandatory"
)

# Get theory info
tcard = theory_card.load(theoryid)
if tcard["DAMP"] == 1:
if not "DAMPPOWERc" in tcard or not "DAMPPOWERb" in tcard:
raise InconsistentInputsError(
"If DAMP is set, set also DAMPPOWERb and DAMPPOWERc"
)
else:
tcard["DAMPPOWERb"] = 0
tcard["DAMPPOWERc"] = 0
# Getting the paths to the grids
grids_name = grids_names(configs.configs["paths"]["ymldb"] / f"{dataset}.yaml")
for grid in grids_name:
# Checking if it already exists
new_fk_path = configs.configs["paths"]["fktables"] / str(theoryid) / grid
if new_fk_path.exists():
if not overwrite:
rich.print(
f"[green]Success:[/] skipping existing FK Table {new_fk_path}"
)
return
fonll.produce_combined_fk(
*(
cfgpath(str(name), grid)
for name in (
ffns3,
ffn03,
ffns4til,
ffns4bar,
ffn04,
ffns5til,
ffns5bar,
)
),
theoryid,
damp=(tcard["DAMP"], tcard["DAMPPOWERc"], tcard["DAMPPOWERb"]),
cfg=cfg,
)
if new_fk_path.exists():
rich.print(f"[green]Success:[/] Wrote FK table to {new_fk_path}")
else:
rich.print(f"[red]Failure:[/]")


@command.command("fonll_tcards")
@click.argument("theoryID", type=int)
@config_setting
def fonll_tcards(theoryid, cfg):
"""Produce the FONLL tcards starting from the original tcard given by the theoryID."""
path = configs.detect(cfg)
base_configs = configs.load(path)
configs.configs = configs.defaults(base_configs)
tcard = theory_card.load(theoryid)
tcard_parent_path = theory_card.path(theoryid).parent
if "FONLL" not in tcard["FNS"]:
raise TheoryCardError("The theorycard does not correspond to an FONLL scheme.")
fonll.dump_tcards(tcard, tcard_parent_path, theoryid)
1 change: 1 addition & 0 deletions src/pineko/cli/opcard.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""CLI entry point to the operator card generation."""

import pathlib

import click
Expand Down
Loading

0 comments on commit 91c3a1a

Please sign in to comment.