Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -42,7 +42,7 @@ jobs:
uses: actions/cache@v3
with:
path: data_files
key: data_files-v4
key: data_files-v5
- name: Download data files
if: steps.cache-data_files.outputs.cache-hit != 'true'
run: |
Expand Down
270 changes: 270 additions & 0 deletions benchmarks/bench_evolution_consistency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
import pathlib

import eko
import numpy as np
import pineappl
import pytest
from nnpdf_data import THEORY_CARDS_PATH
from nnpdf_data.theorydbutils import fetch_theory
from pineappl.grid import Grid
from pineappl.subgrid import ImportSubgridV1

from pineko import check

HERA225 = "HERA_NC_225GEV_EP_SIGMARED"
HERA318 = "HERA_NC_318GEV_EP_SIGMARED"


def test_no_central_order(test_files, toy_xfx, toy_alphas):
grid_path = pathlib.Path(f"{test_files}/data/grids/400/{HERA225}.pineappl.lz4")
if not grid_path.exists():
pytest.fail("Test grid not found")

template_grid = Grid.read(str(grid_path))

template_subgrid = None
for b in range(template_grid.bins()):
for c in range(len(template_grid.channels())):
for o in range(len(template_grid.orders())):
sub = template_grid.subgrid(o, b, c)
if sub.is_empty():
continue

node_values = sub.node_values
if len(node_values) < 2:
continue
shape = tuple(len(v) for v in node_values)
if any(s == 0 for s in shape):
continue
template_subgrid = sub
break
if template_subgrid:
break
if template_subgrid:
break

if not template_subgrid:
pytest.skip("Could not find a non-empty subgrid in template!")

order_0 = pineappl.boc.Order(0, 0, 0, 0, 0)
order_1 = pineappl.boc.Order(1, 0, 0, 0, 0)

grid_zeroed = Grid(
pid_basis=template_grid.pid_basis,
channels=[pineappl.boc.Channel(c) for c in template_grid.channels()],
orders=[order_0, order_1],
bins=template_grid.bwfl(),
convolutions=template_grid.convolutions,
interpolations=template_grid.interpolations,
kinematics=template_grid.kinematics,
scale_funcs=template_grid.scales,
)

grid_opt = Grid(
pid_basis=template_grid.pid_basis,
channels=[pineappl.boc.Channel(c) for c in template_grid.channels()],
orders=[order_1],
bins=template_grid.bwfl(),
convolutions=template_grid.convolutions,
interpolations=template_grid.interpolations,
kinematics=template_grid.kinematics,
scale_funcs=template_grid.scales,
)

node_values = template_subgrid.node_values
shape = tuple(len(v) for v in node_values)
data_1 = np.random.rand(*shape)
subgrid_1 = ImportSubgridV1(array=data_1, node_values=node_values)
data_0 = np.zeros(shape)
subgrid_0 = ImportSubgridV1(array=data_0, node_values=node_values)

for b in range(template_grid.bins()):
for c in range(len(template_grid.channels())):
grid_zeroed.set_subgrid(0, b, c, subgrid_0.into())
grid_zeroed.set_subgrid(1, b, c, subgrid_1.into())
grid_opt.set_subgrid(0, b, c, subgrid_1.into())

mask_zeroed = pineappl.boc.Order.create_mask(grid_zeroed.orders(), 2, 0, True)
mask_opt = pineappl.boc.Order.create_mask(grid_opt.orders(), 2, 0, True)
pdg_convs = template_grid.convolutions
xfxs = [toy_xfx] * len(pdg_convs)

res_zeroed = grid_zeroed.convolve(pdg_convs, xfxs, toy_alphas, mask_zeroed)
res_opt = grid_opt.convolve(pdg_convs, xfxs, toy_alphas, mask_opt)

np.testing.assert_allclose(res_zeroed, res_opt)


def test_evolution_no_central_order(test_4100001000, tmp_path, toy_xfx):
"""Check that evolution with a real EKO gives identical results for zeroed
vs optimized central order grids."""
from pineko import evolve

# Use theory 4100001000 which we know is consistent
tcard_meta = fetch_theory(THEORY_CARDS_PATH, 41000010)
grid_path = pathlib.Path(f"{test_4100001000}/grids/{HERA318}.pineappl.lz4")
eko_path = pathlib.Path(f"{test_4100001000}/ekos/{HERA318}.tar")

# Grid 1: Zeroed central order. Zero out template grid order at (3,0,0,0,0).
grid_zeroed = Grid.read(str(grid_path))
target_order = (3, 0, 0, 0, 0)
order_idx = None
for i, o in enumerate(grid_zeroed.orders()):
if o.as_tuple() == target_order:
order_idx = i
break

if order_idx is None:
pytest.fail(f"Target order {target_order} not found in grid")

for b in range(grid_zeroed.bins()):
for c in range(len(grid_zeroed.channels())):
sub = grid_zeroed.subgrid(order_idx, b, c)
if sub.is_empty():
continue

nv = sub.node_values
if len(nv) > 0:
shape = tuple(len(v) for v in nv)
sub_zero = ImportSubgridV1(array=np.zeros(shape), node_values=nv)
grid_zeroed.set_subgrid(order_idx, b, c, sub_zero.into())

# Grid 2: Optimized (removed) central order
grid_opt = Grid.read(str(grid_path))
grid_opt.delete_orders([order_idx])

with eko.EKO.read(eko_path) as operator:
operators = [operator]
fk_zeroed_path = tmp_path / "fk_zeroed.pineappl.lz4"
fk_opt_path = tmp_path / "fk_opt.pineappl.lz4"

evolve.evolve_grid(
grid_zeroed,
operators,
str(fk_zeroed_path),
max_as=4,
max_al=0,
xir=1.0,
xif=1.0,
xia=1.0,
theory_meta=tcard_meta,
)

evolve.evolve_grid(
grid_opt,
operators,
str(fk_opt_path),
max_as=4,
max_al=0,
xir=1.0,
xif=1.0,
xia=1.0,
theory_meta=tcard_meta,
)

# Compare resulting FK tables
fk_zeroed = pineappl.fk_table.FkTable.read(str(fk_zeroed_path))
fk_opt = pineappl.fk_table.FkTable.read(str(fk_opt_path))

res_zeroed = fk_zeroed.convolve(
fk_zeroed.convolutions,
[toy_xfx] * len(fk_zeroed.convolutions),
)
res_opt = fk_opt.convolve(
fk_opt.convolutions,
[toy_xfx] * len(fk_opt.convolutions),
)

np.testing.assert_allclose(res_zeroed, res_opt)


def test_contains_sv_empty_grid_orders():
class EmptyGrid:
def orders(self):
return []

available, max_as_effective = check.contains_sv(
EmptyGrid(),
max_as=4,
max_al=0,
sv_type=check.Scale.REN,
)
assert available is check.AvailableAtMax.BOTH
assert max_as_effective == 0


def test_evolution_no_orders(test_4100001000, tmp_path, toy_xfx):
"""Compare evolution of: (a) a grid with orders, but all subgrids explicitly
set to zero with (b) the same grid after deleting all orders (no orders at all).

This test effectively checks how to construct a completely empty FK table from
a completely empty grid.
"""
from pineko import evolve

tcard_meta = fetch_theory(THEORY_CARDS_PATH, 41000010)
grid_path = pathlib.Path(f"{test_4100001000}/grids/{HERA318}.pineappl.lz4")
eko_path = pathlib.Path(f"{test_4100001000}/ekos/{HERA318}.tar")

if not (grid_path.exists() and eko_path.exists()):
pytest.skip("Test data not found")

def zero_all_subgrids(grid: Grid) -> None:
for o in range(len(grid.orders())):
for b in range(grid.bins()):
for c in range(len(grid.channels())):
sub = grid.subgrid(o, b, c)
if sub.is_empty():
continue
nv = sub.node_values
shape = tuple(len(v) for v in nv)
sub_zero = ImportSubgridV1(array=np.zeros(shape), node_values=nv)
grid.set_subgrid(o, b, c, sub_zero.into())

grid_zeroed = Grid.read(str(grid_path))
zero_all_subgrids(grid_zeroed)

grid_no_orders = Grid.read(str(grid_path))
grid_no_orders.delete_orders(list(range(len(grid_no_orders.orders()))))

with eko.EKO.read(eko_path) as operator:
fk_zeroed_path = tmp_path / "fk_zeroed_subgrids_no_orders_ref.pineappl.lz4"
fk_no_orders_path = tmp_path / "fk_no_orders.pineappl.lz4"

evolve.evolve_grid(
grid_zeroed,
[operator],
str(fk_zeroed_path),
max_as=4,
max_al=0,
xir=1.0,
xif=1.0,
xia=1.0,
theory_meta=tcard_meta,
)

evolve.evolve_grid(
grid_no_orders,
[operator],
str(fk_no_orders_path),
max_as=4,
max_al=0,
xir=1.0,
xif=1.0,
xia=1.0,
theory_meta=tcard_meta,
)

fk_zeroed = pineappl.fk_table.FkTable.read(str(fk_zeroed_path))
fk_no_orders = pineappl.fk_table.FkTable.read(str(fk_no_orders_path))

res_zeroed = fk_zeroed.convolve(
fk_zeroed.convolutions,
[toy_xfx] * len(fk_zeroed.convolutions),
)
res_no_orders = fk_no_orders.convolve(
fk_no_orders.convolutions,
[toy_xfx] * len(fk_no_orders.convolutions),
)

np.testing.assert_allclose(res_zeroed, res_no_orders)
25 changes: 25 additions & 0 deletions benchmarks/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ def test_files():
return pathlib.Path(__file__).parents[0] / "data_files/"


@pytest.fixture
def test_4100001000():
return pathlib.Path(__file__).parents[0] / "4100001000/"


@pytest.fixture
def test_empty_proj(test_files):
path = test_files / "empty_proj/"
Expand Down Expand Up @@ -65,3 +70,23 @@ def wrapped(newdir):
os.chdir(prevdir)

return wrapped


@pytest.fixture
def toy_xfx():
"""Toy PDF callable."""

def xfx(pid, x, q2):
return 1.0

return xfx


@pytest.fixture
def toy_alphas():
"""Toy alpha_s callable."""

def alphas(q2):
return 1.0

return alphas
1 change: 1 addition & 0 deletions download_test_data.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
wget -r -np -nH --cut-dirs=1 -l 4 -e robots=off --no-verbose -R index.* https://data.nnpdf.science/pineko/theory_productions/
wget -r -np -nH --cut-dirs=1 -l 4 -e robots=off --no-verbose -P benchmarks -R index.* https://data.nnpdf.science/pineko/data_files/
wget -r -np -nH --cut-dirs=1 -l 4 -e robots=off --no-verbose -P benchmarks -R index.* https://data.nnpdf.science/pineko/fakepdfs/
wget -r -np -nH --cut-dirs=1 -l 4 -e robots=off --no-verbose -P benchmarks -R index.* https://data.nnpdf.science/pineko/4100001000/
Loading
Loading