diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e719ff4423..25c5dad19a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,7 +1,10 @@ # A single CI script with github workflow to test NNPDF, and upload the conda package and documentation name: Test conda package -on: [push] +on: + push: + branches-ignore: + - update-pineappl-v1 concurrency: group: ${{ github.head_ref || github.ref }} diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 62a07ce62f..f4064f5cb0 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -36,7 +36,6 @@ requirements: - requests - prompt_toolkit - validobj - - pineappl >=0.8.2 - eko >=0.14.2 - fiatlux - sphinx >=5.0.2 diff --git a/pyproject.toml b/pyproject.toml index d4f135d44c..6a673ea912 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,7 @@ vp-deltachi2 = "validphys.scripts.vp_deltachi2:main" # Generic dependencies (i.e., validphys) python = "^3.9" matplotlib = "^3.9" -pineappl = "^0.8.2" +pineappl = { git = "https://github.com/NNPDF/pineappl.git", branch = "v1-file-format", subdirectory = "pineappl_py" } pandas = "*" numpy = "*" validobj = "*" diff --git a/validphys2/src/validphys/coredata.py b/validphys2/src/validphys/coredata.py index 46a1cab7c6..68d8490707 100644 --- a/validphys2/src/validphys/coredata.py +++ b/validphys2/src/validphys/coredata.py @@ -68,7 +68,7 @@ class FKTableData: ndata: int xgrid: np.ndarray sigma: pd.DataFrame - convolution_types: tuple[str] = None + convolution_types: Optional[tuple[str]] = None metadata: dict = dataclasses.field(default_factory=dict, repr=False) protected: bool = False @@ -206,7 +206,6 @@ def determine_pdfs(self, pdf): conv_pdfs = [] for convolution_type in self.convolution_types: - # Check the type of convolutions that the fktable is asking for and match it to the PDF if convolution_type == "UnpolPDF": if pdf.is_polarized: @@ -214,18 +213,19 @@ def determine_pdfs(self, pdf): raise ValueError( "The FKTable asked for an unpolarized PDF but received only polarized PDFs" ) - conv_pdfs.append(pdf.unpolarized_bc.make_only_cv()) else: conv_pdfs.append(pdf) - elif convolution_type == "PolPDF": if not pdf.is_polarized: raise ValueError( - """The FKTable asked for a polarized PDF, but the PDF received cannot be understood as polarized. - When using a polarized PDF make sure to include a boundary condition `unpolarized_bc: ` whenever needed (`t0`, `dataspecs`...).""" + """The FKTable asked for a polarized PDF, but the PDF received cannot be understood + as polarized. When using a polarized PDF make sure to include a boundary condition + `unpolarized_bc: ` whenever needed (`t0`, `dataspecs`...).""" ) conv_pdfs.append(pdf) + else: # Other scenarios (such as `time_like`) should be implemented as another `elif` statement + raise ValueError("The convolution type is not recognized!") return conv_pdfs diff --git a/validphys2/src/validphys/photon/structure_functions.py b/validphys2/src/validphys/photon/structure_functions.py index 73b45f4746..25c24a05f3 100644 --- a/validphys2/src/validphys/photon/structure_functions.py +++ b/validphys2/src/validphys/photon/structure_functions.py @@ -43,7 +43,7 @@ def __init__(self, path_to_fktable, pdfs): self.q2_max = max(q2) - predictions = self.fktable.convolve_with_one(2212, pdfs.xfxQ2) + predictions = self.fktable.convolve(pdg_convs=self.fktable.convolutions, xfxs=[pdfs.xfxQ2]) grid2D = predictions.reshape(len(x), len(q2)) self.interpolator = RectBivariateSpline(x, q2, grid2D) diff --git a/validphys2/src/validphys/pineparser.py b/validphys2/src/validphys/pineparser.py index d7dd4488a8..e8d3c9e245 100644 --- a/validphys2/src/validphys/pineparser.py +++ b/validphys2/src/validphys/pineparser.py @@ -75,20 +75,41 @@ def _pinelumi_to_columns(pine_luminosity, hadronic): ) flav_size = len(evol_basis_pids) columns = [] + # TODO: Extend this to deal with a generic number of convolutions if hadronic: for i, j in pine_luminosity: idx = evol_basis_pids.index(i) jdx = evol_basis_pids.index(j) columns.append(flav_size * idx + jdx) else: - # The proton might come from both sides - try: - columns = [evol_basis_pids.index(i) for _, i in pine_luminosity] - except ValueError: - columns = [evol_basis_pids.index(i) for i, _ in pine_luminosity] + # Now for DIS, there is only ONE single PID + columns = [evol_basis_pids.index(i[0]) for i in pine_luminosity] return columns +def _get_convolution_types(convolutions): + """Get the type of convolutions from for the given FK table. + + Parameters + ---------- + convolutions: list[pineappl.convolutions.Conv] + a list of PineAPPL object containing the types of convolutions + + Returns + ------- + tuple(str): a tuple of string containing whose elements are either + `UnpolPDF` or `PolPDF` + """ + # TODO: Extend the following to deal with `time_like` FFs + convolution_types = [] + for convolution in convolutions: + if convolution.conv_type.polarized: + convolution_types.append("PolPDF") + else: + convolution_types.append("UnpolPDF") + return tuple(convolution_types) + + def get_yaml_information(yaml_file, theorypath): """Reads the yaml information from a yaml compound file @@ -155,26 +176,22 @@ def pineappl_reader(fkspec): # Extract metadata from the first grid pine_rep = pines[0] - # Is it hadronic? (at the moment only hadronic and DIS are considered) - try: - parton1 = pine_rep.key_values()["convolution_particle_1"] - parton2 = pine_rep.key_values()["convolution_particle_2"] - except KeyError: - # Old pineappl FKTables used `initial_state` instead of `convolution_particle` - parton1 = pine_rep.key_values()["initial_state_1"] - parton2 = pine_rep.key_values()["initial_state_2"] - hadronic = parton1 == parton2 - - # NOTE: while the following can accept any number of convolutions, at the moment only - # 1 (DIS) or 2 (hadronic) are implemented. - # In the case of DIS grids, convolution 1 refers to the hadron - conv_types = [pine_rep.key_values().get("convolution_type_1", "UnpolPDF")] - if hadronic: - # Sanity check (in case at some point we start fitting things that are not protons) - if parton1 != "2212": - raise ValueError("vp can only read hadronic fktables with 2 protons!") + # Get the convolution types for this FK table + convolutions = pine_rep.convolutions + convolution_types = _get_convolution_types(convolutions) + + # Is it hadronic? For the time being, hadronic is defined with `len(convolutions) == 2`. + # Hadronic could also involve 3 convolutions in processes such as `pp->H` (with FFs). + # DIS FK table now only contains ONE single convolutions. + hadronic = len(convolutions) == 2 + # For the time being, allow only hadronic with identical initial-state protons + if hadronic and (convolutions[0].pid != 2212 or convolutions[1].pid != 2212): + raise ValueError("Only two identical protons in the initial-state are allowed.") - conv_types.append(pine_rep.key_values().get("convolution_type_2", "UnpolPDF")) + # TODO: While now any arbittrary number of convolutions is allowed, for the time being, + # raise Errors when the number of convolutions is more than 2. + if len(convolutions) > 2: + raise ValueError("Only FK tables with maximum 2 convolutions are allowed.") Q0 = np.sqrt(pine_rep.muf2()) xgrid = np.array([]) @@ -212,6 +229,9 @@ def pineappl_reader(fkspec): # Read the table, remove bin normalization and apply cfactors raw_fktable = (cfprod * p.table().T / p.bin_normalizations()).T + # If it is a DIS FK table then we need to expand the dimension + if not hadronic: + raw_fktable = np.expand_dims(raw_fktable, axis=-1) n = raw_fktable.shape[0] # Apply possible per-fktable fixes @@ -272,7 +292,7 @@ def pineappl_reader(fkspec): sigma=sigma, ndata=ndata, Q0=Q0, - convolution_types=tuple(conv_types), + convolution_types=convolution_types, metadata=fkspec.metadata, hadronic=hadronic, xgrid=xgrid, diff --git a/validphys2/src/validphys/tests/photon/test_structurefunctions.py b/validphys2/src/validphys/tests/photon/test_structurefunctions.py index f3bba28d0d..0cc9fadfbd 100644 --- a/validphys2/src/validphys/tests/photon/test_structurefunctions.py +++ b/validphys2/src/validphys/tests/photon/test_structurefunctions.py @@ -1,5 +1,6 @@ import numpy as np -import pineappl +from pineappl.convolutions import Conv, ConvType +from pineappl.fk_table import FkTable from validphys.api import API from validphys.core import PDF as PDFset @@ -35,7 +36,12 @@ def bin_left(self, i): else: return 0 - def convolve_with_one(self, pdgid, xfxQ2): + @property + def convolutions(self): + convtype = ConvType(polarized=False, time_like=False) + return [Conv(conv_type=convtype, pid=2212)] + + def convolve(self, pdg_convs, xfxs): return np.zeros((10, 10)) @@ -63,7 +69,7 @@ def test_zero_pdfs(): def test_zero_grid(monkeypatch): "test that a zero grid gives a zero structure function" # patching pineappl.fk_table.FkTable to use ZeroFKTable - monkeypatch.setattr(pineappl.fk_table.FkTable, "read", ZeroFKTable) + monkeypatch.setattr(FkTable, "read", ZeroFKTable) pdfs = PDFset(PDF).load() structurefunc = sf.InterpStructureFunction("", pdfs.central_member) for x in np.geomspace(1e-4, 1.0, 10): @@ -96,10 +102,10 @@ def test_interpolation_grid(): for kind in ["F2", "FL"]: tmp = "fastkernel/FIATLUX_DIS_" + kind + ".pineappl.lz4" path_to_fktable = test_theory.path / tmp - fktable = pineappl.fk_table.FkTable.read(path_to_fktable) + fktable = FkTable.read(path_to_fktable) x = np.unique(fktable.bin_left(1)) q2 = np.unique(fktable.bin_left(0)) - predictions = fktable.convolve_with_one(2212, pdfs.members[replica].xfxQ2) + predictions = fktable.convolve(fktable.convolutions, [pdfs.members[replica].xfxQ2]) grid2D = predictions.reshape(len(x), len(q2)) struct_func = sf.InterpStructureFunction(path_to_fktable, pdfs.members[replica])