diff --git a/pineappl_py/tests/test_fk_table.py b/pineappl_py/tests/test_fk_table.py index cec07f7e..f32f4340 100644 --- a/pineappl_py/tests/test_fk_table.py +++ b/pineappl_py/tests/test_fk_table.py @@ -5,6 +5,8 @@ """ import numpy as np +import pytest +import subprocess from pineappl.boc import Channel, Kinematics from pineappl.convolutions import Conv, ConvType from pineappl.fk_table import FkTable @@ -15,6 +17,34 @@ from typing import List +@pytest.fixture +def download_fktable(tmp_path_factory): + def _download_fk(fkname: str) -> None: + download_dir = tmp_path_factory.mktemp("data") + file_path = download_dir / f"{fkname}" + args = [ + "wget", + "--no-verbose", + "--no-clobber", + "-P", + f"{download_dir}", + f"https://data.nnpdf.science/pineappl/test-data/{fkname}", + ] + + try: + _ = subprocess.run( + args, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + return file_path + except OSError as error: + msg = f"Failed to execute the command {args}." + raise EnvironmentError(msg) from error + + return _download_fk + + class TestFkTable: def fake_grid( self, @@ -35,18 +65,24 @@ def fake_grid( max=1e8, nodes=40, order=3, + reweight_meth="noreweight", + map="applgrid_h0", ), # Interpolation on the Scale Interp( min=2e-7, max=1.0, nodes=50, order=3, + reweight_meth="applgrid", + map="applgrid_f2", ), # Interpolation on x1 momentum fraction Interp( min=2e-7, max=1.0, nodes=50, order=3, + reweight_meth="applgrid", + map="applgrid_f2", ), # Interpolation on x2 momentum fraction ] bin_limits = np.array(bins) @@ -60,7 +96,7 @@ def fake_grid( kinematics=kinematics, ) - def test_convolve_with_one(self): + def test_convolve(self): # Define convolution types and the initial state hadrons # We consider an initial state Polarized Proton h = ConvType(polarized=True, time_like=False) @@ -87,24 +123,89 @@ def test_convolve_with_one(self): g.set_subgrid(0, 0, 0, subgrid.into()) fk = FkTable(g) # Convert Grid -> FkTable np.testing.assert_allclose( - fk.convolve_with_one( - pdg_conv=h_conv, - xfx=lambda pid, x, q2: 0.0, + fk.convolve( + pdg_convs=[h_conv], + xfxs=[lambda pid, x, q2: 0.0], ), [0.0] * 2, ) np.testing.assert_allclose( - fk.convolve_with_one( - pdg_conv=h_conv, - xfx=lambda pid, x, q2: 1.0, + fk.convolve( + pdg_convs=[h_conv], + xfxs=[lambda pid, x, q2: 1.0], ), [5e7 / 9999, 0.0], ) - def test_convolve_with_two(self): - # TODO - pass + def test_unpolarized_convolution( + self, + download_fktable, + fkname: str = "CMSTTBARTOT8TEV-TOPDIFF8TEVTOT.pineappl.lz4", + ): + """Check the convolution of an actual FK table that involves two + symmetrical unpolarized protons: + """ + expected_results = [3.72524538e04] + fk_table = download_fktable(f"{fkname}") + fk = FkTable.read(fk_table) + + # Convolution object of the 1st hadron - Polarized + h = ConvType(polarized=False, time_like=False) + h_conv = Conv(conv_type=h, pid=2212) + + # Define the Toy Unpolarized PDF set + def _unpolarized_pdf(pid, x, q2): + return 1.0 - def test_convolve_with_many(self): - # TODO - pass + np.testing.assert_allclose( + fk.convolve( + pdg_convs=[h_conv, h_conv], + xfxs=[_unpolarized_pdf, _unpolarized_pdf], + ), + expected_results, + ) + + def test_polarized_convolution( + self, + download_fktable, + fkname: str = "GRID_STAR_WMWP_510GEV_WM-AL-POL.pineappl.lz4", + ): + """Check the convolution of an actual FK table that involves two + different initial states: + - 1st hadron: polarized proton + - 2nd hadron: unpolarized proton + """ + expected_results = [ + -1.00885071e6, + -2.40862657e5, + -1.66407218e5, + -2.96098362e5, + -5.67594297e5, + +6.59245015e4, + ] + fk_table = download_fktable(f"{fkname}") + fk = FkTable.read(fk_table) + + # Convolution object of the 1st hadron - Polarized + h1 = ConvType(polarized=True, time_like=False) + h1_conv = Conv(conv_type=h1, pid=2212) + + # Convolution object of the 2nd hadron - Unpolarized + h2 = ConvType(polarized=False, time_like=False) + h2_conv = Conv(conv_type=h2, pid=2212) + + # Define the Toy Polarized PDF set + def _polarized_pdf(pid, x, q2): + return 2.0 + + # Define the Toy Unpolarized PDF set + def _unpolarized_pdf(pid, x, q2): + return 1.0 + + np.testing.assert_allclose( + fk.convolve( + pdg_convs=[h1_conv, h2_conv], + xfxs=[_polarized_pdf, _unpolarized_pdf], + ), + expected_results, + ) diff --git a/pineappl_py/tests/test_grid.py b/pineappl_py/tests/test_grid.py index 875a2ea9..9160cb11 100644 --- a/pineappl_py/tests/test_grid.py +++ b/pineappl_py/tests/test_grid.py @@ -11,7 +11,7 @@ from typing import List # Construct the type of convolutions and the convolution object -# We assume unpolarized proton PDF +# We assume unpolarized protons in the initial state TYPECONV = ConvType(polarized=False, time_like=False) CONVOBJECT = Conv(conv_type=TYPECONV, pid=2212) @@ -20,6 +20,76 @@ CHANNELS = [Channel(UP_ANTIUP_CHANNEL)] ORDERS = [Order(3, 0, 0, 0, 0)] +# Testing specs for Convolution checks. Each element of the list is +# a tuple with two elements where the first element is a dictionary +# whose keys are the arguments of the `convolve` function and the +# second element is the expected results. +REF_VALUE = 5e6 / 9999 +TESTING_SPECS = [ + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 0.0, lambda pid, x, q2: 0.0], + "alphas": lambda q2: 0.0, + }, + [0.0] * 2, + ), # fixed alphas(Q2) == 0.0 + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], + "alphas": lambda q2: 1.0, + }, + [REF_VALUE, 0.0], + ), # fixed alphas(Q2) == 1.0 + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], + "alphas": lambda q2: 2.0, + }, + [2**3 * REF_VALUE, 0.0], + ), # fixed alphas(Q2) == 2.0 + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], + "alphas": lambda q2: 1.0, + "bin_indices": [0], + }, + [REF_VALUE], + ), # block first Bin without argument + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], + "alphas": lambda q2: 1.0, + "bin_indices": [0], + "order_mask": [False], + }, + [0.0], + ), # block first Bin with order_mask + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], + "alphas": lambda q2: 1.0, + "bin_indices": [0], + "channel_mask": [False], + }, + [0.0], + ), # block first Bin with channel_mask + ( + { + "pdg_convs": [CONVOBJECT, CONVOBJECT], + "xfxs": [lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], + "alphas": lambda q2: 1.0, + "bin_indices": [1], + }, + [0.0], + ), # second Bin is empty +] + class TestGrid: def fake_grid( @@ -27,9 +97,8 @@ def fake_grid( channels: List[Channel] = CHANNELS, orders: List[Order] = ORDERS, bins: List[float] = [1e-7, 1e-3, 1], + convolutions: List[Conv] = [CONVOBJECT, CONVOBJECT], ) -> Grid: - # We assume symmetrical proton-proton in the initial state - convolutions = [CONVOBJECT, CONVOBJECT] # Define the kinematics. Kinematics are defined as a list of items. # 1st item: factorization and renormalization scale # 2nd item: parton momentum fraction of the 1st convolution @@ -126,7 +195,8 @@ def test_bins(self): np.testing.assert_allclose(g.bin_left(1), [2, 3]) np.testing.assert_allclose(g.bin_right(1), [3, 5]) - def test_convolve_with_two(self): + @pytest.mark.parametrize("params,expected", TESTING_SPECS) + def test_toy_convolution(self, params, expected): g = self.fake_grid() # Fill the subgrid-part of the GRID object @@ -141,93 +211,15 @@ def test_convolve_with_two(self): g.set_subgrid(0, 0, 0, subgrid.into()) # Check the convolutions of the GRID - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 0.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 0.0, - alphas=lambda q2: 0.0, - ), - [0.0] * 2, - ) - v = 5e6 / 9999 - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 1.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 1.0, - alphas=lambda q2: 1.0, - ), - [v, 0.0], - ) - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 1.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 1.0, - alphas=lambda q2: 2.0, - ), - [2**3 * v, 0.0], - ) - np.testing.assert_allclose( - g.convolve( - pdg_convs=[CONVOBJECT, CONVOBJECT], - xfxs=[lambda pid, x, q2: 1.0, lambda pid, x, q2: 1.0], - alphas=lambda q2: 2.0, - ), - [2**3 * v, 0.0], - ) # Test using the generalized convolution - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 1.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 1.0, - alphas=lambda q2: 1.0, - bin_indices=[0], - ), - [v], - ) - # block first bins with additional args - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 1.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 1.0, - alphas=lambda q2: 1.0, - bin_indices=[0], - order_mask=[False], - ), - [0.0], - ) - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 1.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 1.0, - alphas=lambda q2: 1.0, - bin_indices=[0], - channel_mask=[False], - ), - [0.0], - ) - # second bin is empty - np.testing.assert_allclose( - g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: 1.0, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: 1.0, - alphas=lambda q2: 1.0, - bin_indices=[1], - ), - [0.0], - ) + np.testing.assert_allclose(g.convolve(**params), expected) + + def test_unpolarized_convolution(self): + # TODO + pass + + def test_polarized_convolution(self): + # TODO + pass def test_io(self, tmp_path): g = self.fake_grid() @@ -250,11 +242,9 @@ def test_fill(self): weight=10, ) # Peform convolutions using Toy LHPDF & AlphasQ2 functions - res = g.convolve_with_two( - pdg_conv1=CONVOBJECT, - xfx1=lambda pid, x, q2: x, - pdg_conv2=CONVOBJECT, - xfx2=lambda pid, x, q2: x, + res = g.convolve( + pdg_convs=[CONVOBJECT, CONVOBJECT], + xfxs=[lambda pid, x, q2: x, lambda pid, x, q2: x], alphas=lambda q2: 1.0, ) pytest.approx(res) == 0.0 diff --git a/pineappl_py/tests/test_subgrid.py b/pineappl_py/tests/test_subgrid.py index c560499a..5c2dd3b2 100644 --- a/pineappl_py/tests/test_subgrid.py +++ b/pineappl_py/tests/test_subgrid.py @@ -75,9 +75,9 @@ def convolve_grid(q2_min: float = Q2_MIN) -> Grid: ntuple=[0.2, 0.2, 10], weight=0.5, ) - return grid.convolve_with_one( - pdg_conv=CONVOBJECT, - xfx=pdf.xfxQ, + return grid.convolve( + pdg_convs=[CONVOBJECT], + xfxs=[pdf.xfxQ], alphas=pdf.alphasQ, )